Home | History | Annotate | Download | only in nano
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2013 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 package com.google.protobuf.nano;
     32 
     33 import java.io.IOException;
     34 import java.lang.reflect.Array;
     35 import java.util.ArrayList;
     36 import java.util.List;
     37 
     38 /**
     39  * Represents an extension.
     40  *
     41  * @author bduff (at) google.com (Brian Duff)
     42  * @author maxtroy (at) google.com (Max Cai)
     43  * @param <M> the type of the extendable message this extension is for.
     44  * @param <T> the Java type of the extension; see {@link #clazz}.
     45  */
     46 public class Extension<M extends ExtendableMessageNano<M>, T> {
     47 
     48     /*
     49      * Because we typically only define message-typed extensions, the Extension class hierarchy is
     50      * designed as follows, to allow a big amount of code in this file to be removed by ProGuard:
     51      *
     52      *            Extension          // ready to use for message/group typed extensions
     53      *                
     54      *                |
     55      *       PrimitiveExtension      // for primitive/enum typed extensions
     56      */
     57 
     58     public static final int TYPE_DOUBLE   = InternalNano.TYPE_DOUBLE;
     59     public static final int TYPE_FLOAT    = InternalNano.TYPE_FLOAT;
     60     public static final int TYPE_INT64    = InternalNano.TYPE_INT64;
     61     public static final int TYPE_UINT64   = InternalNano.TYPE_UINT64;
     62     public static final int TYPE_INT32    = InternalNano.TYPE_INT32;
     63     public static final int TYPE_FIXED64  = InternalNano.TYPE_FIXED64;
     64     public static final int TYPE_FIXED32  = InternalNano.TYPE_FIXED32;
     65     public static final int TYPE_BOOL     = InternalNano.TYPE_BOOL;
     66     public static final int TYPE_STRING   = InternalNano.TYPE_STRING;
     67     public static final int TYPE_GROUP    = InternalNano.TYPE_GROUP;
     68     public static final int TYPE_MESSAGE  = InternalNano.TYPE_MESSAGE;
     69     public static final int TYPE_BYTES    = InternalNano.TYPE_BYTES;
     70     public static final int TYPE_UINT32   = InternalNano.TYPE_UINT32;
     71     public static final int TYPE_ENUM     = InternalNano.TYPE_ENUM;
     72     public static final int TYPE_SFIXED32 = InternalNano.TYPE_SFIXED32;
     73     public static final int TYPE_SFIXED64 = InternalNano.TYPE_SFIXED64;
     74     public static final int TYPE_SINT32   = InternalNano.TYPE_SINT32;
     75     public static final int TYPE_SINT64   = InternalNano.TYPE_SINT64;
     76 
     77     /**
     78      * Creates an {@code Extension} of the given message type and tag number.
     79      * Should be used by the generated code only.
     80      *
     81      * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
     82      * @deprecated use {@link #createMessageTyped(int, Class, long)} instead.
     83      */
     84     @Deprecated
     85     public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
     86             Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
     87         return new Extension<M, T>(type, clazz, tag, false);
     88     }
     89 
     90     // Note: these create...() methods take a long for the tag parameter,
     91     // because tags are represented as unsigned ints, and these values exist
     92     // in generated code as long values. However, they can fit in 32-bits, so
     93     // it's safe to cast them to int without loss of precision.
     94 
     95     /**
     96      * Creates an {@code Extension} of the given message type and tag number.
     97      * Should be used by the generated code only.
     98      *
     99      * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
    100      */
    101     public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
    102             Extension<M, T> createMessageTyped(int type, Class<T> clazz, long tag) {
    103         return new Extension<M, T>(type, clazz, (int) tag, false);
    104     }
    105 
    106     /**
    107      * Creates a repeated {@code Extension} of the given message type and tag number.
    108      * Should be used by the generated code only.
    109      *
    110      * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
    111      */
    112     public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
    113             Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag) {
    114         return new Extension<M, T[]>(type, clazz, (int) tag, true);
    115     }
    116 
    117     /**
    118      * Creates an {@code Extension} of the given primitive type and tag number.
    119      * Should be used by the generated code only.
    120      *
    121      * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
    122      * @param clazz the boxed Java type of this extension
    123      */
    124     public static <M extends ExtendableMessageNano<M>, T>
    125             Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, long tag) {
    126         return new PrimitiveExtension<M, T>(type, clazz, (int) tag, false, 0, 0);
    127     }
    128 
    129     /**
    130      * Creates a repeated {@code Extension} of the given primitive type and tag number.
    131      * Should be used by the generated code only.
    132      *
    133      * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
    134      * @param clazz the Java array type of this extension, with an unboxed component type
    135      */
    136     public static <M extends ExtendableMessageNano<M>, T>
    137             Extension<M, T> createRepeatedPrimitiveTyped(
    138                     int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag) {
    139         return new PrimitiveExtension<M, T>(type, clazz, (int) tag, true,
    140             (int) nonPackedTag, (int) packedTag);
    141     }
    142 
    143     /**
    144      * Protocol Buffer type of this extension; one of the {@code TYPE_} constants.
    145      */
    146     protected final int type;
    147 
    148     /**
    149      * Java type of this extension. For a singular extension, this is the boxed Java type for the
    150      * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose
    151      * component type is the unboxed Java type for {@link #type}. For example, for a singular
    152      * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a
    153      * repeated {@code int32} extension, this equals {@code int[].class}.
    154      */
    155     protected final Class<T> clazz;
    156 
    157     /**
    158      * Tag number of this extension. The data should be viewed as an unsigned 32-bit value.
    159      */
    160     public final int tag;
    161 
    162     /**
    163      * Whether this extension is repeated.
    164      */
    165     protected final boolean repeated;
    166 
    167     private Extension(int type, Class<T> clazz, int tag, boolean repeated) {
    168         this.type = type;
    169         this.clazz = clazz;
    170         this.tag = tag;
    171         this.repeated = repeated;
    172     }
    173 
    174     /**
    175      * Returns the value of this extension stored in the given list of unknown fields, or
    176      * {@code null} if no unknown fields matches this extension.
    177      *
    178      * @param unknownFields a list of {@link UnknownFieldData}. All of the elements must have a tag
    179      *                      that matches this Extension's tag.
    180      *
    181      */
    182     final T getValueFrom(List<UnknownFieldData> unknownFields) {
    183         if (unknownFields == null) {
    184             return null;
    185         }
    186         return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
    187     }
    188 
    189     private T getRepeatedValueFrom(List<UnknownFieldData> unknownFields) {
    190         // For repeated extensions, read all matching unknown fields in their original order.
    191         List<Object> resultList = new ArrayList<Object>();
    192         for (int i = 0; i < unknownFields.size(); i++) {
    193             UnknownFieldData data = unknownFields.get(i);
    194             if (data.bytes.length != 0) {
    195                 readDataInto(data, resultList);
    196             }
    197         }
    198 
    199         int resultSize = resultList.size();
    200         if (resultSize == 0) {
    201             return null;
    202         } else {
    203             T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
    204             for (int i = 0; i < resultSize; i++) {
    205                 Array.set(result, i, resultList.get(i));
    206             }
    207             return result;
    208         }
    209     }
    210 
    211     private T getSingularValueFrom(List<UnknownFieldData> unknownFields) {
    212         // For singular extensions, get the last piece of data stored under this extension.
    213         if (unknownFields.isEmpty()) {
    214             return null;
    215         }
    216         UnknownFieldData lastData = unknownFields.get(unknownFields.size() - 1);
    217         return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
    218     }
    219 
    220     protected Object readData(CodedInputByteBufferNano input) {
    221         // This implementation is for message/group extensions.
    222         Class<?> messageType = repeated ? clazz.getComponentType() : clazz;
    223         try {
    224             switch (type) {
    225                 case TYPE_GROUP:
    226                     MessageNano group = (MessageNano) messageType.newInstance();
    227                     input.readGroup(group, WireFormatNano.getTagFieldNumber(tag));
    228                     return group;
    229                 case TYPE_MESSAGE:
    230                     MessageNano message = (MessageNano) messageType.newInstance();
    231                     input.readMessage(message);
    232                     return message;
    233                 default:
    234                     throw new IllegalArgumentException("Unknown type " + type);
    235             }
    236         } catch (InstantiationException e) {
    237             throw new IllegalArgumentException(
    238                     "Error creating instance of class " + messageType, e);
    239         } catch (IllegalAccessException e) {
    240             throw new IllegalArgumentException(
    241                     "Error creating instance of class " + messageType, e);
    242         } catch (IOException e) {
    243             throw new IllegalArgumentException("Error reading extension field", e);
    244         }
    245     }
    246 
    247     protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
    248         // This implementation is for message/group extensions.
    249         resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
    250     }
    251 
    252     void writeTo(Object value, CodedOutputByteBufferNano output) throws IOException {
    253         if (repeated) {
    254             writeRepeatedData(value, output);
    255         } else {
    256             writeSingularData(value, output);
    257         }
    258     }
    259 
    260     protected void writeSingularData(Object value, CodedOutputByteBufferNano out) {
    261         // This implementation is for message/group extensions.
    262         try {
    263             out.writeRawVarint32(tag);
    264             switch (type) {
    265                 case TYPE_GROUP:
    266                     MessageNano groupValue = (MessageNano) value;
    267                     int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
    268                     out.writeGroupNoTag(groupValue);
    269                     // The endgroup tag must be included in the data payload.
    270                     out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
    271                     break;
    272                 case TYPE_MESSAGE:
    273                     MessageNano messageValue = (MessageNano) value;
    274                     out.writeMessageNoTag(messageValue);
    275                     break;
    276                 default:
    277                     throw new IllegalArgumentException("Unknown type " + type);
    278             }
    279         } catch (IOException e) {
    280             // Should not happen
    281             throw new IllegalStateException(e);
    282         }
    283     }
    284 
    285     protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
    286         // This implementation is for non-packed extensions.
    287         int arrayLength = Array.getLength(array);
    288         for (int i = 0; i < arrayLength; i++) {
    289             Object element = Array.get(array, i);
    290             if (element != null) {
    291                 writeSingularData(element, output);
    292             }
    293         }
    294     }
    295 
    296     int computeSerializedSize(Object value) {
    297         if (repeated) {
    298             return computeRepeatedSerializedSize(value);
    299         } else {
    300             return computeSingularSerializedSize(value);
    301         }
    302     }
    303 
    304     protected int computeRepeatedSerializedSize(Object array) {
    305         // This implementation is for non-packed extensions.
    306         int size = 0;
    307         int arrayLength = Array.getLength(array);
    308         for (int i = 0; i < arrayLength; i++) {
    309             Object element = Array.get(array, i);
    310             if (element != null) {
    311                 size += computeSingularSerializedSize(Array.get(array, i));
    312             }
    313         }
    314         return size;
    315     }
    316 
    317     protected int computeSingularSerializedSize(Object value) {
    318         // This implementation is for message/group extensions.
    319         int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
    320         switch (type) {
    321             case TYPE_GROUP:
    322                 MessageNano groupValue = (MessageNano) value;
    323                 return CodedOutputByteBufferNano.computeGroupSize(fieldNumber, groupValue);
    324             case TYPE_MESSAGE:
    325                 MessageNano messageValue = (MessageNano) value;
    326                 return CodedOutputByteBufferNano.computeMessageSize(fieldNumber, messageValue);
    327             default:
    328                 throw new IllegalArgumentException("Unknown type " + type);
    329         }
    330     }
    331 
    332     /**
    333      * Represents an extension of a primitive (including enum) type. If there is no primitive
    334      * extensions, this subclass will be removable by ProGuard.
    335      */
    336     private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T>
    337             extends Extension<M, T> {
    338 
    339         /**
    340          * Tag of a piece of non-packed data from the wire compatible with this extension.
    341          */
    342         private final int nonPackedTag;
    343 
    344         /**
    345          * Tag of a piece of packed data from the wire compatible with this extension.
    346          * 0 if the type of this extension is not packable.
    347          */
    348         private final int packedTag;
    349 
    350         public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated,
    351                 int nonPackedTag, int packedTag) {
    352             super(type, clazz, tag, repeated);
    353             this.nonPackedTag = nonPackedTag;
    354             this.packedTag = packedTag;
    355         }
    356 
    357         @Override
    358         protected Object readData(CodedInputByteBufferNano input) {
    359             try {
    360               return input.readPrimitiveField(type);
    361             } catch (IOException e) {
    362                 throw new IllegalArgumentException("Error reading extension field", e);
    363             }
    364         }
    365 
    366         @Override
    367         protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
    368             // This implementation is for primitive typed extensions,
    369             // which can read both packed and non-packed data.
    370             if (data.tag == nonPackedTag) {
    371                 resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
    372             } else {
    373                 CodedInputByteBufferNano buffer =
    374                         CodedInputByteBufferNano.newInstance(data.bytes);
    375                 try {
    376                     buffer.pushLimit(buffer.readRawVarint32()); // length limit
    377                 } catch (IOException e) {
    378                     throw new IllegalArgumentException("Error reading extension field", e);
    379                 }
    380                 while (!buffer.isAtEnd()) {
    381                     resultList.add(readData(buffer));
    382                 }
    383             }
    384         }
    385 
    386         @Override
    387         protected final void writeSingularData(Object value, CodedOutputByteBufferNano output) {
    388             try {
    389                 output.writeRawVarint32(tag);
    390                 switch (type) {
    391                     case TYPE_DOUBLE:
    392                         Double doubleValue = (Double) value;
    393                         output.writeDoubleNoTag(doubleValue);
    394                         break;
    395                     case TYPE_FLOAT:
    396                         Float floatValue = (Float) value;
    397                         output.writeFloatNoTag(floatValue);
    398                         break;
    399                     case TYPE_INT64:
    400                         Long int64Value = (Long) value;
    401                         output.writeInt64NoTag(int64Value);
    402                         break;
    403                     case TYPE_UINT64:
    404                         Long uint64Value = (Long) value;
    405                         output.writeUInt64NoTag(uint64Value);
    406                         break;
    407                     case TYPE_INT32:
    408                         Integer int32Value = (Integer) value;
    409                         output.writeInt32NoTag(int32Value);
    410                         break;
    411                     case TYPE_FIXED64:
    412                         Long fixed64Value = (Long) value;
    413                         output.writeFixed64NoTag(fixed64Value);
    414                         break;
    415                     case TYPE_FIXED32:
    416                         Integer fixed32Value = (Integer) value;
    417                         output.writeFixed32NoTag(fixed32Value);
    418                         break;
    419                     case TYPE_BOOL:
    420                         Boolean boolValue = (Boolean) value;
    421                         output.writeBoolNoTag(boolValue);
    422                         break;
    423                     case TYPE_STRING:
    424                         String stringValue = (String) value;
    425                         output.writeStringNoTag(stringValue);
    426                         break;
    427                     case TYPE_BYTES:
    428                         byte[] bytesValue = (byte[]) value;
    429                         output.writeBytesNoTag(bytesValue);
    430                         break;
    431                     case TYPE_UINT32:
    432                         Integer uint32Value = (Integer) value;
    433                         output.writeUInt32NoTag(uint32Value);
    434                         break;
    435                     case TYPE_ENUM:
    436                         Integer enumValue = (Integer) value;
    437                         output.writeEnumNoTag(enumValue);
    438                         break;
    439                     case TYPE_SFIXED32:
    440                         Integer sfixed32Value = (Integer) value;
    441                         output.writeSFixed32NoTag(sfixed32Value);
    442                         break;
    443                     case TYPE_SFIXED64:
    444                         Long sfixed64Value = (Long) value;
    445                         output.writeSFixed64NoTag(sfixed64Value);
    446                         break;
    447                     case TYPE_SINT32:
    448                         Integer sint32Value = (Integer) value;
    449                         output.writeSInt32NoTag(sint32Value);
    450                         break;
    451                     case TYPE_SINT64:
    452                         Long sint64Value = (Long) value;
    453                         output.writeSInt64NoTag(sint64Value);
    454                         break;
    455                     default:
    456                         throw new IllegalArgumentException("Unknown type " + type);
    457                 }
    458             } catch (IOException e) {
    459                 // Should not happen
    460                 throw new IllegalStateException(e);
    461             }
    462         }
    463 
    464         @Override
    465         protected void writeRepeatedData(Object array, CodedOutputByteBufferNano output) {
    466             if (tag == nonPackedTag) {
    467                 // Use base implementation for non-packed data
    468                 super.writeRepeatedData(array, output);
    469             } else if (tag == packedTag) {
    470                 // Packed. Note that the array element type is guaranteed to be primitive, so there
    471                 // won't be any null elements, so no null check in this block.
    472                 int arrayLength = Array.getLength(array);
    473                 int dataSize = computePackedDataSize(array);
    474 
    475                 try {
    476                     output.writeRawVarint32(tag);
    477                     output.writeRawVarint32(dataSize);
    478                     switch (type) {
    479                         case TYPE_BOOL:
    480                             for (int i = 0; i < arrayLength; i++) {
    481                                 output.writeBoolNoTag(Array.getBoolean(array, i));
    482                             }
    483                             break;
    484                         case TYPE_FIXED32:
    485                             for (int i = 0; i < arrayLength; i++) {
    486                                 output.writeFixed32NoTag(Array.getInt(array, i));
    487                             }
    488                             break;
    489                         case TYPE_SFIXED32:
    490                             for (int i = 0; i < arrayLength; i++) {
    491                                 output.writeSFixed32NoTag(Array.getInt(array, i));
    492                             }
    493                             break;
    494                         case TYPE_FLOAT:
    495                             for (int i = 0; i < arrayLength; i++) {
    496                                 output.writeFloatNoTag(Array.getFloat(array, i));
    497                             }
    498                             break;
    499                         case TYPE_FIXED64:
    500                             for (int i = 0; i < arrayLength; i++) {
    501                                 output.writeFixed64NoTag(Array.getLong(array, i));
    502                             }
    503                             break;
    504                         case TYPE_SFIXED64:
    505                             for (int i = 0; i < arrayLength; i++) {
    506                                 output.writeSFixed64NoTag(Array.getLong(array, i));
    507                             }
    508                             break;
    509                         case TYPE_DOUBLE:
    510                             for (int i = 0; i < arrayLength; i++) {
    511                                 output.writeDoubleNoTag(Array.getDouble(array, i));
    512                             }
    513                             break;
    514                         case TYPE_INT32:
    515                             for (int i = 0; i < arrayLength; i++) {
    516                                 output.writeInt32NoTag(Array.getInt(array, i));
    517                             }
    518                             break;
    519                         case TYPE_SINT32:
    520                             for (int i = 0; i < arrayLength; i++) {
    521                                 output.writeSInt32NoTag(Array.getInt(array, i));
    522                             }
    523                             break;
    524                         case TYPE_UINT32:
    525                             for (int i = 0; i < arrayLength; i++) {
    526                                 output.writeUInt32NoTag(Array.getInt(array, i));
    527                             }
    528                             break;
    529                         case TYPE_INT64:
    530                             for (int i = 0; i < arrayLength; i++) {
    531                                 output.writeInt64NoTag(Array.getLong(array, i));
    532                             }
    533                             break;
    534                         case TYPE_SINT64:
    535                             for (int i = 0; i < arrayLength; i++) {
    536                                 output.writeSInt64NoTag(Array.getLong(array, i));
    537                             }
    538                             break;
    539                         case TYPE_UINT64:
    540                             for (int i = 0; i < arrayLength; i++) {
    541                                 output.writeUInt64NoTag(Array.getLong(array, i));
    542                             }
    543                             break;
    544                         case TYPE_ENUM:
    545                             for (int i = 0; i < arrayLength; i++) {
    546                                 output.writeEnumNoTag(Array.getInt(array, i));
    547                             }
    548                             break;
    549                         default:
    550                             throw new IllegalArgumentException("Unpackable type " + type);
    551                     }
    552                 } catch (IOException e) {
    553                     // Should not happen.
    554                     throw new IllegalStateException(e);
    555                 }
    556             } else {
    557                 throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
    558                         + ", unequal to both non-packed variant " + nonPackedTag
    559                         + " and packed variant " + packedTag);
    560             }
    561         }
    562 
    563         private int computePackedDataSize(Object array) {
    564             int dataSize = 0;
    565             int arrayLength = Array.getLength(array);
    566             switch (type) {
    567                 case TYPE_BOOL:
    568                     // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
    569                     dataSize = arrayLength;
    570                     break;
    571                 case TYPE_FIXED32:
    572                 case TYPE_SFIXED32:
    573                 case TYPE_FLOAT:
    574                     dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
    575                     break;
    576                 case TYPE_FIXED64:
    577                 case TYPE_SFIXED64:
    578                 case TYPE_DOUBLE:
    579                     dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
    580                     break;
    581                 case TYPE_INT32:
    582                     for (int i = 0; i < arrayLength; i++) {
    583                         dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
    584                                 Array.getInt(array, i));
    585                     }
    586                     break;
    587                 case TYPE_SINT32:
    588                     for (int i = 0; i < arrayLength; i++) {
    589                         dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
    590                                 Array.getInt(array, i));
    591                     }
    592                     break;
    593                 case TYPE_UINT32:
    594                     for (int i = 0; i < arrayLength; i++) {
    595                         dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
    596                                 Array.getInt(array, i));
    597                     }
    598                     break;
    599                 case TYPE_INT64:
    600                     for (int i = 0; i < arrayLength; i++) {
    601                         dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
    602                                 Array.getLong(array, i));
    603                     }
    604                     break;
    605                 case TYPE_SINT64:
    606                     for (int i = 0; i < arrayLength; i++) {
    607                         dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
    608                                 Array.getLong(array, i));
    609                     }
    610                     break;
    611                 case TYPE_UINT64:
    612                     for (int i = 0; i < arrayLength; i++) {
    613                         dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
    614                                 Array.getLong(array, i));
    615                     }
    616                     break;
    617                 case TYPE_ENUM:
    618                     for (int i = 0; i < arrayLength; i++) {
    619                         dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
    620                                 Array.getInt(array, i));
    621                     }
    622                     break;
    623                 default:
    624                     throw new IllegalArgumentException("Unexpected non-packable type " + type);
    625             }
    626             return dataSize;
    627         }
    628 
    629         @Override
    630         protected int computeRepeatedSerializedSize(Object array) {
    631             if (tag == nonPackedTag) {
    632                 // Use base implementation for non-packed data
    633                 return super.computeRepeatedSerializedSize(array);
    634             } else if (tag == packedTag) {
    635                 // Packed.
    636                 int dataSize = computePackedDataSize(array);
    637                 int payloadSize =
    638                         dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
    639                 return payloadSize + CodedOutputByteBufferNano.computeRawVarint32Size(tag);
    640             } else {
    641                 throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
    642                         + ", unequal to both non-packed variant " + nonPackedTag
    643                         + " and packed variant " + packedTag);
    644             }
    645         }
    646 
    647         @Override
    648         protected final int computeSingularSerializedSize(Object value) {
    649             int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
    650             switch (type) {
    651                 case TYPE_DOUBLE:
    652                     Double doubleValue = (Double) value;
    653                     return CodedOutputByteBufferNano.computeDoubleSize(fieldNumber, doubleValue);
    654                 case TYPE_FLOAT:
    655                     Float floatValue = (Float) value;
    656                     return CodedOutputByteBufferNano.computeFloatSize(fieldNumber, floatValue);
    657                 case TYPE_INT64:
    658                     Long int64Value = (Long) value;
    659                     return CodedOutputByteBufferNano.computeInt64Size(fieldNumber, int64Value);
    660                 case TYPE_UINT64:
    661                     Long uint64Value = (Long) value;
    662                     return CodedOutputByteBufferNano.computeUInt64Size(fieldNumber, uint64Value);
    663                 case TYPE_INT32:
    664                     Integer int32Value = (Integer) value;
    665                     return CodedOutputByteBufferNano.computeInt32Size(fieldNumber, int32Value);
    666                 case TYPE_FIXED64:
    667                     Long fixed64Value = (Long) value;
    668                     return CodedOutputByteBufferNano.computeFixed64Size(fieldNumber, fixed64Value);
    669                 case TYPE_FIXED32:
    670                     Integer fixed32Value = (Integer) value;
    671                     return CodedOutputByteBufferNano.computeFixed32Size(fieldNumber, fixed32Value);
    672                 case TYPE_BOOL:
    673                     Boolean boolValue = (Boolean) value;
    674                     return CodedOutputByteBufferNano.computeBoolSize(fieldNumber, boolValue);
    675                 case TYPE_STRING:
    676                     String stringValue = (String) value;
    677                     return CodedOutputByteBufferNano.computeStringSize(fieldNumber, stringValue);
    678                 case TYPE_BYTES:
    679                     byte[] bytesValue = (byte[]) value;
    680                     return CodedOutputByteBufferNano.computeBytesSize(fieldNumber, bytesValue);
    681                 case TYPE_UINT32:
    682                     Integer uint32Value = (Integer) value;
    683                     return CodedOutputByteBufferNano.computeUInt32Size(fieldNumber, uint32Value);
    684                 case TYPE_ENUM:
    685                     Integer enumValue = (Integer) value;
    686                     return CodedOutputByteBufferNano.computeEnumSize(fieldNumber, enumValue);
    687                 case TYPE_SFIXED32:
    688                     Integer sfixed32Value = (Integer) value;
    689                     return CodedOutputByteBufferNano.computeSFixed32Size(fieldNumber,
    690                             sfixed32Value);
    691                 case TYPE_SFIXED64:
    692                     Long sfixed64Value = (Long) value;
    693                     return CodedOutputByteBufferNano.computeSFixed64Size(fieldNumber,
    694                             sfixed64Value);
    695                 case TYPE_SINT32:
    696                     Integer sint32Value = (Integer) value;
    697                     return CodedOutputByteBufferNano.computeSInt32Size(fieldNumber, sint32Value);
    698                 case TYPE_SINT64:
    699                     Long sint64Value = (Long) value;
    700                     return CodedOutputByteBufferNano.computeSInt64Size(fieldNumber, sint64Value);
    701                 default:
    702                     throw new IllegalArgumentException("Unknown type " + type);
    703             }
    704         }
    705     }
    706 }
    707