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