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@google.com (Brian Duff)
42  * @author maxtroy@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>
createMessageTyped(int type, Class<T> clazz, int tag)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>
createMessageTyped(int type, Class<T> clazz, long tag)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>
createRepeatedMessageTyped(int type, Class<T[]> clazz, long tag)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>
createPrimitiveTyped(int type, Class<T> clazz, long tag)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>
createRepeatedPrimitiveTyped( int type, Class<T> clazz, long tag, long nonPackedTag, long packedTag)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 
Extension(int type, Class<T> clazz, int tag, boolean repeated)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      */
getValueFrom(List<UnknownFieldData> unknownFields)182     final T getValueFrom(List<UnknownFieldData> unknownFields) {
183         if (unknownFields == null) {
184             return null;
185         }
186         return repeated ? getRepeatedValueFrom(unknownFields) : getSingularValueFrom(unknownFields);
187     }
188 
getRepeatedValueFrom(List<UnknownFieldData> unknownFields)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 
getSingularValueFrom(List<UnknownFieldData> unknownFields)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 
readData(CodedInputByteBufferNano input)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 
readDataInto(UnknownFieldData data, List<Object> resultList)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 
writeTo(Object value, CodedOutputByteBufferNano output)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 
writeSingularData(Object value, CodedOutputByteBufferNano out)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 
writeRepeatedData(Object array, CodedOutputByteBufferNano output)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 
computeSerializedSize(Object value)296     int computeSerializedSize(Object value) {
297         if (repeated) {
298             return computeRepeatedSerializedSize(value);
299         } else {
300             return computeSingularSerializedSize(value);
301         }
302     }
303 
computeRepeatedSerializedSize(Object array)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 
computeSingularSerializedSize(Object value)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 
PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated, int nonPackedTag, int packedTag)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
readData(CodedInputByteBufferNano input)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
readDataInto(UnknownFieldData data, List<Object> resultList)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
writeSingularData(Object value, CodedOutputByteBufferNano output)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
writeRepeatedData(Object array, CodedOutputByteBufferNano output)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 
computePackedDataSize(Object array)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
computeRepeatedSerializedSize(Object array)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
computeSingularSerializedSize(Object value)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