| // Protocol Buffers - Google's data interchange format |
| // Copyright 2013 Google Inc. All rights reserved. |
| // https://developers.google.com/protocol-buffers/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package com.google.protobuf.nano; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Array; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Represents an extension. |
| * |
| * @author bduff@google.com (Brian Duff) |
| * @author maxtroy@google.com (Max Cai) |
| * @param <M> the type of the extendable message this extension is for. |
| * @param <T> the Java type of the extension; see {@link #clazz}. |
| */ |
| public class Extension<M extends ExtendableMessageNano<M>, T> { |
| |
| /* |
| * Because we typically only define message-typed extensions, the Extension class hierarchy is |
| * designed as follows, to allow a big amount of code in this file to be removed by ProGuard: |
| * |
| * Extension // ready to use for message/group typed extensions |
| * Δ |
| * | |
| * PrimitiveExtension // for primitive/enum typed extensions |
| */ |
| |
| public static final int TYPE_DOUBLE = InternalNano.TYPE_DOUBLE; |
| public static final int TYPE_FLOAT = InternalNano.TYPE_FLOAT; |
| public static final int TYPE_INT64 = InternalNano.TYPE_INT64; |
| public static final int TYPE_UINT64 = InternalNano.TYPE_UINT64; |
| public static final int TYPE_INT32 = InternalNano.TYPE_INT32; |
| public static final int TYPE_FIXED64 = InternalNano.TYPE_FIXED64; |
| public static final int TYPE_FIXED32 = InternalNano.TYPE_FIXED32; |
| public static final int TYPE_BOOL = InternalNano.TYPE_BOOL; |
| public static final int TYPE_STRING = InternalNano.TYPE_STRING; |
| public static final int TYPE_GROUP = InternalNano.TYPE_GROUP; |
| public static final int TYPE_MESSAGE = InternalNano.TYPE_MESSAGE; |
| public static final int TYPE_BYTES = InternalNano.TYPE_BYTES; |
| public static final int TYPE_UINT32 = InternalNano.TYPE_UINT32; |
| public static final int TYPE_ENUM = InternalNano.TYPE_ENUM; |
| public static final int TYPE_SFIXED32 = InternalNano.TYPE_SFIXED32; |
| public static final int TYPE_SFIXED64 = InternalNano.TYPE_SFIXED64; |
| public static final int TYPE_SINT32 = InternalNano.TYPE_SINT32; |
| public static final int TYPE_SINT64 = InternalNano.TYPE_SINT64; |
| |
| /** |
| * Creates an {@code Extension} of the given message type and tag number. |
| * Should be used by the generated code only. |
| * |
| * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP} |
| * @deprecated use {@link #createMessageTyped(int, Class, long)} instead. |
| */ |
| @Deprecated |
| public static <M extends ExtendableMessageNano<M>, T extends MessageNano> |
| Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) { |
| return new Extension<M, T>(type, clazz, tag, false); |
| } |
| |
| // Note: these create...() methods take a long for the tag parameter, |
| // because tags are represented as unsigned ints, and these values exist |
| // in generated code as long values. However, they can fit in 32-bits, so |
| // it's safe to cast them to int without loss of precision. |
| |
| /** |
| * Creates an {@code Extension} of the given message type and tag number. |
| * Should be used by the generated code only. |
| * |
| * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP} |
| */ |
| public static <M extends ExtendableMessageNano<M>, T extends MessageNano> |
| Extension<M, T> createMessageTyped(int type, Class<T> clazz, long tag) { |
| return new Extension<M, T>(type, clazz, (int) tag, false); |
| } |
| |
| /** |
| * Creates a repeated {@code Extension} of the given message type and tag number. |
| * Should be used by the generated code only. |
| * |
| * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP} |
| */ |
| public static <M extends ExtendableMessageNano<M>, T extends MessageNano> |
| Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) { |
| return new Extension<M, T[]>(type, clazz, (int) tag, true); |
| } |
| |
| /** |
| * Creates an {@code Extension} of the given primitive type and tag number. |
| * Should be used by the generated code only. |
| * |
| * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP} |
| * @param clazz the boxed Java type of this extension |
| */ |
| public static <M extends ExtendableMessageNano<M>, T> |
| Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) { |
| return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0); |
| } |
| |
| /** |
| * Creates a repeated {@code Extension} of the given primitive type and tag number. |
| * Should be used by the generated code only. |
| * |
| * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP} |
| * @param clazz the Java array type of this extension, with an unboxed component type |
| */ |
| public static <M extends ExtendableMessageNano<M>, T> |
| Extension<M, T> createRepeatedPrimitiveTyped( |
| int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag) { |
| return new PrimitiveExtension<M, T>(type, clazz, (int) tag, true, |
| (int) nonPackedTag, (int) packedTag); |
| } |
| |
| /** |
| * Protocol Buffer type of this extension; one of the {@code TYPE_} constants. |
| */ |
| protected final int type; |
| |
| /** |
| * Java type of this extension. For a singular extension, this is the boxed Java type for the |
| * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose |
| * component type is the unboxed Java type for {@link #type}. For example, for a singular |
| * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a |
| * repeated {@code int32} extension, this equals {@code int[].class}. |
| */ |
| protected final Class<T> clazz; |
| |
| /** |
| * Tag number of this extension. The data should be viewed as an unsigned 32-bit value. |
| */ |
| public final int tag; |
| |
| /** |
| * Whether this extension is repeated. |
| */ |
| protected final boolean repeated; |
| |
| private Extension(int type, Class<T> clazz, int tag, boolean repeated) { |
| this.type = type; |
| this.clazz = clazz; |
| this.tag = tag; |
| this.repeated = repeated; |
| } |
| |
| /** |
| * Returns the value of this extension stored in the given list of unknown fields, or |
| * {@code null} if no unknown fields matches this extension. |
| * |
| * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag |
| * that matches this Extension's tag. |
| * |
| */ |
| final T getValueFrom(List<UnknownFieldData> unknownFields) { |
| if (unknownFields == null) { |
| return null; |
| } |
| return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields); |
| } |
| |
| private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) { |
| // For repeated extensions, read all matching unknown fields in their original order. |
| List<Object> resultList = new ArrayList<Object>(); |
| for (int i = 0; i < unknownFields.size(); i++) { |
| UnknownFieldData data = unknownFields.get(i); |
| if (data.bytes.length != 0) { |
| readDataInto(data, resultList); |
| } |
| } |
| |
| int resultSize = resultList.size(); |
| if (resultSize == 0) { |
| return null; |
| } else { |
| T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize)); |
| for (int i = 0; i < resultSize; i++) { |
| Array.set(result, i, resultList.get(i)); |
| } |
| return result; |
| } |
| } |
| |
| private T getSingularValueFrom(List<UnknownFieldData> unknownFields) { |
| // For singular extensions, get the last piece of data stored under this extension. |
| if (unknownFields.isEmpty()) { |
| return null; |
| } |
| UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1); |
| return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes))); |
| } |
| |
| protected Object readData(CodedInputByteBufferNano input) { |
| // This implementation is for message/group extensions. |
| Class<?> messageType = repeated ? clazz.getComponentType() : clazz; |
| try { |
| switch (type) { |
| case TYPE_GROUP: |
| MessageNano group = (MessageNano) messageType.newInstance(); |
| input.readGroup(group, WireFormatNano.getTagFieldNumber(tag)); |
| return group; |
| case TYPE_MESSAGE: |
| MessageNano message = (MessageNano) messageType.newInstance(); |
| input.readMessage(message); |
| return message; |
| default: |
| throw new IllegalArgumentException("Unknown type " + type); |
| } |
| } catch (InstantiationException e) { |
| throw new IllegalArgumentException( |
| "Error creating instance of class " + messageType, e); |
| } catch (IllegalAccessException e) { |
| throw new IllegalArgumentException( |
| "Error creating instance of class " + messageType, e); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Error reading extension field", e); |
| } |
| } |
| |
| protected void readDataInto(UnknownFieldData data, List<Object> resultList) { |
| // This implementation is for message/group extensions. |
| resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes))); |
| } |
| |
| void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException { |
| if (repeated) { |
| writeRepeatedData(value, output); |
| } else { |
| writeSingularData(value, output); |
| } |
| } |
| |
| protected void writeSingularData(Object value, CodedOutputByteBufferNano out) { |
| // This implementation is for message/group extensions. |
| try { |
| out.writeRawVarint32(tag); |
| switch (type) { |
| case TYPE_GROUP: |
| MessageNano groupValue = (MessageNano) value; |
| int fieldNumber = WireFormatNano.getTagFieldNumber(tag); |
| out.writeGroupNoTag(groupValue); |
| // The endgroup tag must be included in the data payload. |
| out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP); |
| break; |
| case TYPE_MESSAGE: |
| MessageNano messageValue = (MessageNano) value; |
| out.writeMessageNoTag(messageValue); |
| break; |
| default: |
| throw new IllegalArgumentException("Unknown type " + type); |
| } |
| } catch (IOException e) { |
| // Should not happen |
| throw new IllegalStateException(e); |
| } |
| } |
| |
| protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) { |
| // This implementation is for non-packed extensions. |
| int arrayLength = Array.getLength(array); |
| for (int i = 0; i < arrayLength; i++) { |
| Object element = Array.get(array, i); |
| if (element != null) { |
| writeSingularData(element, output); |
| } |
| } |
| } |
| |
| int computeSerializedSize(Object value) { |
| if (repeated) { |
| return computeRepeatedSerializedSize(value); |
| } else { |
| return computeSingularSerializedSize(value); |
| } |
| } |
| |
| protected int computeRepeatedSerializedSize(Object array) { |
| // This implementation is for non-packed extensions. |
| int size = 0; |
| int arrayLength = Array.getLength(array); |
| for (int i = 0; i < arrayLength; i++) { |
| Object element = Array.get(array, i); |
| if (element != null) { |
| size += computeSingularSerializedSize(Array.get(array, i)); |
| } |
| } |
| return size; |
| } |
| |
| protected int computeSingularSerializedSize(Object value) { |
| // This implementation is for message/group extensions. |
| int fieldNumber = WireFormatNano.getTagFieldNumber(tag); |
| switch (type) { |
| case TYPE_GROUP: |
| MessageNano groupValue = (MessageNano) value; |
| return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue); |
| case TYPE_MESSAGE: |
| MessageNano messageValue = (MessageNano) value; |
| return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue); |
| default: |
| throw new IllegalArgumentException("Unknown type " + type); |
| } |
| } |
| |
| /** |
| * Represents an extension of a primitive (including enum) type. If there is no primitive |
| * extensions, this subclass will be removable by ProGuard. |
| */ |
| private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T> |
| extends Extension<M, T> { |
| |
| /** |
| * Tag of a piece of non-packed data from the wire compatible with this extension. |
| */ |
| private final int nonPackedTag; |
| |
| /** |
| * Tag of a piece of packed data from the wire compatible with this extension. |
| * 0 if the type of this extension is not packable. |
| */ |
| private final int packedTag; |
| |
| public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated, |
| int nonPackedTag, int packedTag) { |
| super(type, clazz, tag, repeated); |
| this.nonPackedTag = nonPackedTag; |
| this.packedTag = packedTag; |
| } |
| |
| @Override |
| protected Object readData(CodedInputByteBufferNano input) { |
| try { |
| return input.readPrimitiveField(type); |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Error reading extension field", e); |
| } |
| } |
| |
| @Override |
| protected void readDataInto(UnknownFieldData data, List<Object> resultList) { |
| // This implementation is for primitive typed extensions, |
| // which can read both packed and non-packed data. |
| if (data.tag == nonPackedTag) { |
| resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes))); |
| } else { |
| CodedInputByteBufferNano buffer = |
| CodedInputByteBufferNano.newInstance(data.bytes); |
| try { |
| buffer.pushLimit(buffer.readRawVarint32()); // length limit |
| } catch (IOException e) { |
| throw new IllegalArgumentException("Error reading extension field", e); |
| } |
| while (!buffer.isAtEnd()) { |
| resultList.add(readData(buffer)); |
| } |
| } |
| } |
| |
| @Override |
| protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) { |
| try { |
| output.writeRawVarint32(tag); |
| switch (type) { |
| case TYPE_DOUBLE: |
| Double doubleValue = (Double) value; |
| output.writeDoubleNoTag(doubleValue); |
| break; |
| case TYPE_FLOAT: |
| Float floatValue = (Float) value; |
| output.writeFloatNoTag(floatValue); |
| break; |
| case TYPE_INT64: |
| Long int64Value = (Long) value; |
| output.writeInt64NoTag(int64Value); |
| break; |
| case TYPE_UINT64: |
| Long uint64Value = (Long) value; |
| output.writeUInt64NoTag(uint64Value); |
| break; |
| case TYPE_INT32: |
| Integer int32Value = (Integer) value; |
| output.writeInt32NoTag(int32Value); |
| break; |
| case TYPE_FIXED64: |
| Long fixed64Value = (Long) value; |
| output.writeFixed64NoTag(fixed64Value); |
| break; |
| case TYPE_FIXED32: |
| Integer fixed32Value = (Integer) value; |
| output.writeFixed32NoTag(fixed32Value); |
| break; |
| case TYPE_BOOL: |
| Boolean boolValue = (Boolean) value; |
| output.writeBoolNoTag(boolValue); |
| break; |
| case TYPE_STRING: |
| String stringValue = (String) value; |
| output.writeStringNoTag(stringValue); |
| break; |
| case TYPE_BYTES: |
| byte[] bytesValue = (byte[]) value; |
| output.writeBytesNoTag(bytesValue); |
| break; |
| case TYPE_UINT32: |
| Integer uint32Value = (Integer) value; |
| output.writeUInt32NoTag(uint32Value); |
| break; |
| case TYPE_ENUM: |
| Integer enumValue = (Integer) value; |
| output.writeEnumNoTag(enumValue); |
| break; |
| case TYPE_SFIXED32: |
| Integer sfixed32Value = (Integer) value; |
| output.writeSFixed32NoTag(sfixed32Value); |
| break; |
| case TYPE_SFIXED64: |
| Long sfixed64Value = (Long) value; |
| output.writeSFixed64NoTag(sfixed64Value); |
| break; |
| case TYPE_SINT32: |
| Integer sint32Value = (Integer) value; |
| output.writeSInt32NoTag(sint32Value); |
| break; |
| case TYPE_SINT64: |
| Long sint64Value = (Long) value; |
| output.writeSInt64NoTag(sint64Value); |
| break; |
| default: |
| throw new IllegalArgumentException("Unknown type " + type); |
| } |
| } catch (IOException e) { |
| // Should not happen |
| throw new IllegalStateException(e); |
| } |
| } |
| |
| @Override |
| protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) { |
| if (tag == nonPackedTag) { |
| // Use base implementation for non-packed data |
| super.writeRepeatedData(array, output); |
| } else if (tag == packedTag) { |
| // Packed. Note that the array element type is guaranteed to be primitive, so there |
| // won't be any null elements, so no null check in this block. |
| int arrayLength = Array.getLength(array); |
| int dataSize = computePackedDataSize(array); |
| |
| try { |
| output.writeRawVarint32(tag); |
| output.writeRawVarint32(dataSize); |
| switch (type) { |
| case TYPE_BOOL: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeBoolNoTag(Array.getBoolean(array, i)); |
| } |
| break; |
| case TYPE_FIXED32: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeFixed32NoTag(Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_SFIXED32: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeSFixed32NoTag(Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_FLOAT: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeFloatNoTag(Array.getFloat(array, i)); |
| } |
| break; |
| case TYPE_FIXED64: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeFixed64NoTag(Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_SFIXED64: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeSFixed64NoTag(Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_DOUBLE: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeDoubleNoTag(Array.getDouble(array, i)); |
| } |
| break; |
| case TYPE_INT32: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeInt32NoTag(Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_SINT32: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeSInt32NoTag(Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_UINT32: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeUInt32NoTag(Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_INT64: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeInt64NoTag(Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_SINT64: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeSInt64NoTag(Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_UINT64: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeUInt64NoTag(Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_ENUM: |
| for (int i = 0; i < arrayLength; i++) { |
| output.writeEnumNoTag(Array.getInt(array, i)); |
| } |
| break; |
| default: |
| throw new IllegalArgumentException("Unpackable type " + type); |
| } |
| } catch (IOException e) { |
| // Should not happen. |
| throw new IllegalStateException(e); |
| } |
| } else { |
| throw new IllegalArgumentException("Unexpected repeated extension tag " + tag |
| + ", unequal to both non-packed variant " + nonPackedTag |
| + " and packed variant " + packedTag); |
| } |
| } |
| |
| private int computePackedDataSize(Object array) { |
| int dataSize = 0; |
| int arrayLength = Array.getLength(array); |
| switch (type) { |
| case TYPE_BOOL: |
| // Bools are stored as int32 but just as 0 or 1, so 1 byte each. |
| dataSize = arrayLength; |
| break; |
| case TYPE_FIXED32: |
| case TYPE_SFIXED32: |
| case TYPE_FLOAT: |
| dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE; |
| break; |
| case TYPE_FIXED64: |
| case TYPE_SFIXED64: |
| case TYPE_DOUBLE: |
| dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE; |
| break; |
| case TYPE_INT32: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag( |
| Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_SINT32: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag( |
| Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_UINT32: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag( |
| Array.getInt(array, i)); |
| } |
| break; |
| case TYPE_INT64: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag( |
| Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_SINT64: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag( |
| Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_UINT64: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag( |
| Array.getLong(array, i)); |
| } |
| break; |
| case TYPE_ENUM: |
| for (int i = 0; i < arrayLength; i++) { |
| dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag( |
| Array.getInt(array, i)); |
| } |
| break; |
| default: |
| throw new IllegalArgumentException("Unexpected non-packable type " + type); |
| } |
| return dataSize; |
| } |
| |
| @Override |
| protected int computeRepeatedSerializedSize(Object array) { |
| if (tag == nonPackedTag) { |
| // Use base implementation for non-packed data |
| return super.computeRepeatedSerializedSize(array); |
| } else if (tag == packedTag) { |
| // Packed. |
| int dataSize = computePackedDataSize(array); |
| int payloadSize = |
| dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize); |
| return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag); |
| } else { |
| throw new IllegalArgumentException("Unexpected repeated extension tag " + tag |
| + ", unequal to both non-packed variant " + nonPackedTag |
| + " and packed variant " + packedTag); |
| } |
| } |
| |
| @Override |
| protected final int computeSingularSerializedSize(Object value) { |
| int fieldNumber = WireFormatNano.getTagFieldNumber(tag); |
| switch (type) { |
| case TYPE_DOUBLE: |
| Double doubleValue = (Double) value; |
| return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue); |
| case TYPE_FLOAT: |
| Float floatValue = (Float) value; |
| return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue); |
| case TYPE_INT64: |
| Long int64Value = (Long) value; |
| return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value); |
| case TYPE_UINT64: |
| Long uint64Value = (Long) value; |
| return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value); |
| case TYPE_INT32: |
| Integer int32Value = (Integer) value; |
| return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value); |
| case TYPE_FIXED64: |
| Long fixed64Value = (Long) value; |
| return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value); |
| case TYPE_FIXED32: |
| Integer fixed32Value = (Integer) value; |
| return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value); |
| case TYPE_BOOL: |
| Boolean boolValue = (Boolean) value; |
| return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue); |
| case TYPE_STRING: |
| String stringValue = (String) value; |
| return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue); |
| case TYPE_BYTES: |
| byte[] bytesValue = (byte[]) value; |
| return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue); |
| case TYPE_UINT32: |
| Integer uint32Value = (Integer) value; |
| return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value); |
| case TYPE_ENUM: |
| Integer enumValue = (Integer) value; |
| return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue); |
| case TYPE_SFIXED32: |
| Integer sfixed32Value = (Integer) value; |
| return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber, |
| sfixed32Value); |
| case TYPE_SFIXED64: |
| Long sfixed64Value = (Long) value; |
| return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber, |
| sfixed64Value); |
| case TYPE_SINT32: |
| Integer sint32Value = (Integer) value; |
| return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value); |
| case TYPE_SINT64: |
| Long sint64Value = (Long) value; |
| return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value); |
| default: |
| throw new IllegalArgumentException("Unknown type " + type); |
| } |
| } |
| } |
| } |