All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dongliu.prettypb.runtime.utils.ExtensionFieldUtils Maven / Gradle / Ivy

There is a newer version: 0.3.5
Show newest version
package net.dongliu.prettypb.runtime.utils;

import net.dongliu.prettypb.runtime.ExtensionRegistry;
import net.dongliu.prettypb.runtime.ProtoBufDecoder;
import net.dongliu.prettypb.runtime.ProtoBufEncoder;
import net.dongliu.prettypb.runtime.code.ProtoBufReader;
import net.dongliu.prettypb.runtime.code.ProtoBufWriter;
import net.dongliu.prettypb.runtime.exception.UnExpectedEOFException;
import net.dongliu.prettypb.runtime.include.Extendable;
import net.dongliu.prettypb.runtime.include.ExtensionField;
import net.dongliu.prettypb.runtime.include.ProtoType;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * serialize and deSerialize extension fields
 *
 * @author Dong Liu
 */
public class ExtensionFieldUtils {

    /**
     * serialize field
     */
    public static void writeField(ExtensionField extensionField, Object value,
                                  ProtoBufWriter writer) throws IOException {
        if (!extensionField.isRepeated()) {
            writeSingleField(extensionField, value, writer);
        } else if (!extensionField.isPacked()) {
            List list = (List) value;
            for (Object v : list) {
                writeSingleField(extensionField, v, writer);
            }
        } else {
            // packed list
            writePackedListField(extensionField, (List) value, writer);
        }
    }

    private static void writeSingleField(ExtensionField extensionField, Object value,
                                         ProtoBufWriter writer) throws IOException {
        writer.encodeTag(extensionField.getProtoType(), extensionField.getNumber());
        serializeField(extensionField.getProtoType(), extensionField.getClazz(), value, writer);
    }

    private static void writePackedListField(ExtensionField extensionField, List list,
                                             ProtoBufWriter writer) throws IOException {
        writer.encodeTag(ProtoType.packedWireType, extensionField.getNumber());
        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            ProtoBufWriter w = new ProtoBufWriter(os);
            for (Object value : list) {
                serializeField(extensionField.getProtoType(), extensionField.getClazz(), value, w);
            }
            writer.writeBytes(os.toByteArray());
        }
    }

    private static void serializeField(ProtoType protoType, Class clazz, Object value,
                                       ProtoBufWriter writer) throws IOException {
        switch (protoType) {
            case Int32:
                writer.writeVarInt((Integer) value);
                break;
            case SInt32:
                writer.writeVarSInt((Integer) value);
                break;
            case UInt32:
                writer.writeVarInt((Integer) value);
                break;
            case Int64:
                writer.writeVarLong((Long) value);
                break;
            case SInt64:
                writer.writeVarSLong((Long) value);
                break;
            case UInt64:
                writer.writeVarLong((Long) value);
                break;
            case Fixed32:
                writer.writeFixedInt((Integer) value);
                break;
            case SFixed32:
                writer.writeFixedInt((Integer) value);
                break;
            case Fixed64:
                writer.writeFixedLong((Long) value);
                break;
            case SFixed64:
                writer.writeFixedLong((Long) value);
                break;
            case Float:
                writer.writeFloat((Float) value);
                break;
            case Double:
                writer.writeDouble((Double) value);
                break;
            case Bool:
                writer.writeVarInt((Boolean) value ? 1 : 0);
                break;
            case Enum:
                writer.writeVarInt(ProtoUtils.getEnumValue((Enum) value));
                break;
            case String:
                writer.writeString((String) value);
                break;
            case Bytes:
                writer.writeBytes((byte[]) value);
                break;
            case Message:
                writer.writeBytes(ProtoBufEncoder.toBytes(value, (Class) clazz));
                break;
            default:
                throw new RuntimeException("unknown type:" + protoType.name());
        }
    }

    public static void readField(ExtensionField extensionField, ProtoBufReader protoBufReader,
                                 Extendable extendable, ExtensionRegistry extensionRegistry)
            throws IOException {
        if (!extensionField.isRepeated()) {
            extendable.setExtension(extensionField, readObject(extensionField.getProtoType(),
                    extensionField.getClazz(), protoBufReader, extensionRegistry));
        } else if (!extensionField.isPacked()) {
            List list = (List) extendable.getExtension(extensionField);
            if (list == null) {
                list = new ArrayList();
                extendable.setExtension(extensionField, list);
            }
            list.add(readObject(extensionField.getProtoType(), extensionField.getClazz(),
                    protoBufReader, extensionRegistry));
        } else {
            byte[] bytes = protoBufReader.readBytes();
            List list = new ArrayList();
            try (InputStream in = new ByteArrayInputStream(bytes)) {
                ProtoBufReader byteReader = new ProtoBufReader(in);
                while (true) {
                    try {
                        list.add(readObject(extensionField.getProtoType(),
                                extensionField.getClazz(), byteReader, extensionRegistry));
                    } catch (UnExpectedEOFException ignore) {
                        break;
                    }
                }
            }
            extendable.setExtension(extensionField, list);
        }
    }

    private static Object readObject(ProtoType protoType, Class clazz, ProtoBufReader reader,
                                     ExtensionRegistry extensionRegistry) throws IOException {
        switch (protoType) {
            case Int32:
                return reader.readVarInt();
            case SInt32:
                return reader.readVarSInt();
            case UInt32:
                return reader.readVarInt();
            case Int64:
                return reader.readVarLong();
            case SInt64:
                return reader.readVarSLong();
            case UInt64:
                return reader.readVarLong();
            case Fixed32:
                return reader.readFixedInt();
            case SFixed32:
                return reader.readFixedInt();
            case Fixed64:
                return reader.readFixedLong();
            case SFixed64:
                return reader.readFixedLong();
            case Float:
                return reader.readFloat();
            case Double:
                return reader.readDouble();
            case Bool:
                return reader.readVarInt() != 0;
            case Enum:
                return ProtoUtils.parseEnum((Class) clazz, reader.readVarInt());
            case String:
                return reader.readString();
            case Bytes:
                return reader.readBytes();
            case Message:
                byte[] bytes = reader.readBytes();
                return ProtoBufDecoder.fromBytes(clazz, bytes, extensionRegistry);
            default:
                throw new RuntimeException("unknown type:" + protoType.name());
        }
    }
}