- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / java / src / main / java / com / google / protobuf / FieldSet.java
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 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
31 package com.google.protobuf;
32
33 import com.google.protobuf.LazyField.LazyIterator;
34
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41
42 /**
43  * A class which represents an arbitrary set of fields of some message type.
44  * This is used to implement {@link DynamicMessage}, and also to represent
45  * extensions in {@link GeneratedMessage}.  This class is package-private,
46  * since outside users should probably be using {@link DynamicMessage}.
47  *
48  * @author kenton@google.com Kenton Varda
49  */
50 final class FieldSet<FieldDescriptorType extends
51       FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
52   /**
53    * Interface for a FieldDescriptor or lite extension descriptor.  This
54    * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
55    */
56   public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
57       extends Comparable<T> {
58     int getNumber();
59     WireFormat.FieldType getLiteType();
60     WireFormat.JavaType getLiteJavaType();
61     boolean isRepeated();
62     boolean isPacked();
63     Internal.EnumLiteMap<?> getEnumType();
64
65     // If getLiteJavaType() == MESSAGE, this merges a message object of the
66     // type into a builder of the type.  Returns {@code to}.
67     MessageLite.Builder internalMergeFrom(
68         MessageLite.Builder to, MessageLite from);
69   }
70
71   private final SmallSortedMap<FieldDescriptorType, Object> fields;
72   private boolean isImmutable;
73   private boolean hasLazyField = false;
74
75   /** Construct a new FieldSet. */
76   private FieldSet() {
77     this.fields = SmallSortedMap.newFieldMap(16);
78   }
79
80   /**
81    * Construct an empty FieldSet.  This is only used to initialize
82    * DEFAULT_INSTANCE.
83    */
84   private FieldSet(final boolean dummy) {
85     this.fields = SmallSortedMap.newFieldMap(0);
86     makeImmutable();
87   }
88
89   /** Construct a new FieldSet. */
90   public static <T extends FieldSet.FieldDescriptorLite<T>>
91       FieldSet<T> newFieldSet() {
92     return new FieldSet<T>();
93   }
94
95   /** Get an immutable empty FieldSet. */
96   @SuppressWarnings("unchecked")
97   public static <T extends FieldSet.FieldDescriptorLite<T>>
98       FieldSet<T> emptySet() {
99     return DEFAULT_INSTANCE;
100   }
101   @SuppressWarnings("rawtypes")
102   private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
103
104   /** Make this FieldSet immutable from this point forward. */
105   @SuppressWarnings("unchecked")
106   public void makeImmutable() {
107     if (isImmutable) {
108       return;
109     }
110     fields.makeImmutable();
111     isImmutable = true;
112   }
113
114   /**
115    * Returns whether the FieldSet is immutable. This is true if it is the
116    * {@link #emptySet} or if {@link #makeImmutable} were called.
117    *
118    * @return whether the FieldSet is immutable.
119    */
120   public boolean isImmutable() {
121     return isImmutable;
122   }
123
124   /**
125    * Clones the FieldSet. The returned FieldSet will be mutable even if the
126    * original FieldSet was immutable.
127    *
128    * @return the newly cloned FieldSet
129    */
130   @Override
131   public FieldSet<FieldDescriptorType> clone() {
132     // We can't just call fields.clone because List objects in the map
133     // should not be shared.
134     FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
135     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
136       Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
137       FieldDescriptorType descriptor = entry.getKey();
138       clone.setField(descriptor, entry.getValue());
139     }
140     for (Map.Entry<FieldDescriptorType, Object> entry :
141              fields.getOverflowEntries()) {
142       FieldDescriptorType descriptor = entry.getKey();
143       clone.setField(descriptor, entry.getValue());
144     }
145     clone.hasLazyField = hasLazyField;
146     return clone;
147   }
148
149   // =================================================================
150
151   /** See {@link Message.Builder#clear()}. */
152   public void clear() {
153     fields.clear();
154     hasLazyField = false;
155   }
156
157   /**
158    * Get a simple map containing all the fields.
159    */
160   public Map<FieldDescriptorType, Object> getAllFields() {
161     if (hasLazyField) {
162       SmallSortedMap<FieldDescriptorType, Object> result =
163           SmallSortedMap.newFieldMap(16);
164       for (int i = 0; i < fields.getNumArrayEntries(); i++) {
165         cloneFieldEntry(result, fields.getArrayEntryAt(i));
166       }
167       for (Map.Entry<FieldDescriptorType, Object> entry :
168           fields.getOverflowEntries()) {
169         cloneFieldEntry(result, entry);
170       }
171       if (fields.isImmutable()) {
172         result.makeImmutable();
173       }
174       return result;
175     }
176     return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
177   }
178
179   private void cloneFieldEntry(Map<FieldDescriptorType, Object> map,
180       Map.Entry<FieldDescriptorType, Object> entry) {
181     FieldDescriptorType key = entry.getKey();
182     Object value = entry.getValue();
183     if (value instanceof LazyField) {
184       map.put(key, ((LazyField) value).getValue());
185     } else {
186       map.put(key, value);
187     }
188   }
189
190   /**
191    * Get an iterator to the field map. This iterator should not be leaked out
192    * of the protobuf library as it is not protected from mutation when fields
193    * is not immutable.
194    */
195   public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
196     if (hasLazyField) {
197       return new LazyIterator<FieldDescriptorType>(
198           fields.entrySet().iterator());
199     }
200     return fields.entrySet().iterator();
201   }
202
203   /**
204    * Useful for implementing
205    * {@link Message#hasField(Descriptors.FieldDescriptor)}.
206    */
207   public boolean hasField(final FieldDescriptorType descriptor) {
208     if (descriptor.isRepeated()) {
209       throw new IllegalArgumentException(
210         "hasField() can only be called on non-repeated fields.");
211     }
212
213     return fields.get(descriptor) != null;
214   }
215
216   /**
217    * Useful for implementing
218    * {@link Message#getField(Descriptors.FieldDescriptor)}.  This method
219    * returns {@code null} if the field is not set; in this case it is up
220    * to the caller to fetch the field's default value.
221    */
222   public Object getField(final FieldDescriptorType descriptor) {
223     Object o = fields.get(descriptor);
224     if (o instanceof LazyField) {
225       return ((LazyField) o).getValue();
226     }
227     return o;
228   }
229
230   /**
231    * Useful for implementing
232    * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
233    */
234   @SuppressWarnings({"unchecked", "rawtypes"})
235   public void setField(final FieldDescriptorType descriptor,
236                        Object value) {
237     if (descriptor.isRepeated()) {
238       if (!(value instanceof List)) {
239         throw new IllegalArgumentException(
240           "Wrong object type used with protocol message reflection.");
241       }
242
243       // Wrap the contents in a new list so that the caller cannot change
244       // the list's contents after setting it.
245       final List newList = new ArrayList();
246       newList.addAll((List) value);
247       for (final Object element : newList) {
248         verifyType(descriptor.getLiteType(), element);
249       }
250       value = newList;
251     } else {
252       verifyType(descriptor.getLiteType(), value);
253     }
254
255     if (value instanceof LazyField) {
256       hasLazyField = true;
257     }
258     fields.put(descriptor, value);
259   }
260
261   /**
262    * Useful for implementing
263    * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
264    */
265   public void clearField(final FieldDescriptorType descriptor) {
266     fields.remove(descriptor);
267     if (fields.isEmpty()) {
268       hasLazyField = false;
269     }
270   }
271
272   /**
273    * Useful for implementing
274    * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
275    */
276   public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
277     if (!descriptor.isRepeated()) {
278       throw new IllegalArgumentException(
279         "getRepeatedField() can only be called on repeated fields.");
280     }
281
282     final Object value = getField(descriptor);
283     if (value == null) {
284       return 0;
285     } else {
286       return ((List<?>) value).size();
287     }
288   }
289
290   /**
291    * Useful for implementing
292    * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
293    */
294   public Object getRepeatedField(final FieldDescriptorType descriptor,
295                                  final int index) {
296     if (!descriptor.isRepeated()) {
297       throw new IllegalArgumentException(
298         "getRepeatedField() can only be called on repeated fields.");
299     }
300
301     final Object value = getField(descriptor);
302
303     if (value == null) {
304       throw new IndexOutOfBoundsException();
305     } else {
306       return ((List<?>) value).get(index);
307     }
308   }
309
310   /**
311    * Useful for implementing
312    * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
313    */
314   @SuppressWarnings("unchecked")
315   public void setRepeatedField(final FieldDescriptorType descriptor,
316                                final int index,
317                                final Object value) {
318     if (!descriptor.isRepeated()) {
319       throw new IllegalArgumentException(
320         "getRepeatedField() can only be called on repeated fields.");
321     }
322
323     final Object list = getField(descriptor);
324     if (list == null) {
325       throw new IndexOutOfBoundsException();
326     }
327
328     verifyType(descriptor.getLiteType(), value);
329     ((List<Object>) list).set(index, value);
330   }
331
332   /**
333    * Useful for implementing
334    * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
335    */
336   @SuppressWarnings("unchecked")
337   public void addRepeatedField(final FieldDescriptorType descriptor,
338                                final Object value) {
339     if (!descriptor.isRepeated()) {
340       throw new IllegalArgumentException(
341         "addRepeatedField() can only be called on repeated fields.");
342     }
343
344     verifyType(descriptor.getLiteType(), value);
345
346     final Object existingValue = getField(descriptor);
347     List<Object> list;
348     if (existingValue == null) {
349       list = new ArrayList<Object>();
350       fields.put(descriptor, list);
351     } else {
352       list = (List<Object>) existingValue;
353     }
354
355     list.add(value);
356   }
357
358   /**
359    * Verifies that the given object is of the correct type to be a valid
360    * value for the given field.  (For repeated fields, this checks if the
361    * object is the right type to be one element of the field.)
362    *
363    * @throws IllegalArgumentException The value is not of the right type.
364    */
365   private static void verifyType(final WireFormat.FieldType type,
366                                  final Object value) {
367     if (value == null) {
368       throw new NullPointerException();
369     }
370
371     boolean isValid = false;
372     switch (type.getJavaType()) {
373       case INT:          isValid = value instanceof Integer   ; break;
374       case LONG:         isValid = value instanceof Long      ; break;
375       case FLOAT:        isValid = value instanceof Float     ; break;
376       case DOUBLE:       isValid = value instanceof Double    ; break;
377       case BOOLEAN:      isValid = value instanceof Boolean   ; break;
378       case STRING:       isValid = value instanceof String    ; break;
379       case BYTE_STRING:  isValid = value instanceof ByteString; break;
380       case ENUM:
381         // TODO(kenton):  Caller must do type checking here, I guess.
382         isValid = value instanceof Internal.EnumLite;
383         break;
384       case MESSAGE:
385         // TODO(kenton):  Caller must do type checking here, I guess.
386         isValid =
387             (value instanceof MessageLite) || (value instanceof LazyField);
388         break;
389     }
390
391     if (!isValid) {
392       // TODO(kenton):  When chaining calls to setField(), it can be hard to
393       //   tell from the stack trace which exact call failed, since the whole
394       //   chain is considered one line of code.  It would be nice to print
395       //   more information here, e.g. naming the field.  We used to do that.
396       //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
397       //   isn't a big deal, though, since it would only really apply when using
398       //   reflection and generally people don't chain reflection setters.
399       throw new IllegalArgumentException(
400         "Wrong object type used with protocol message reflection.");
401     }
402   }
403
404   // =================================================================
405   // Parsing and serialization
406
407   /**
408    * See {@link Message#isInitialized()}.  Note:  Since {@code FieldSet}
409    * itself does not have any way of knowing about required fields that
410    * aren't actually present in the set, it is up to the caller to check
411    * that all required fields are present.
412    */
413   public boolean isInitialized() {
414     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
415       if (!isInitialized(fields.getArrayEntryAt(i))) {
416         return false;
417       }
418     }
419     for (final Map.Entry<FieldDescriptorType, Object> entry :
420              fields.getOverflowEntries()) {
421       if (!isInitialized(entry)) {
422         return false;
423       }
424     }
425     return true;
426   }
427
428   @SuppressWarnings("unchecked")
429   private boolean isInitialized(
430       final Map.Entry<FieldDescriptorType, Object> entry) {
431     final FieldDescriptorType descriptor = entry.getKey();
432     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
433       if (descriptor.isRepeated()) {
434         for (final MessageLite element:
435                  (List<MessageLite>) entry.getValue()) {
436           if (!element.isInitialized()) {
437             return false;
438           }
439         }
440       } else {
441         Object value = entry.getValue();
442         if (value instanceof MessageLite) {
443           if (!((MessageLite) value).isInitialized()) {
444             return false;
445           }
446         } else if (value instanceof LazyField) {
447           return true;
448         } else {
449           throw new IllegalArgumentException(
450               "Wrong object type used with protocol message reflection.");
451         }
452       }
453     }
454     return true;
455   }
456
457   /**
458    * Given a field type, return the wire type.
459    *
460    * @returns One of the {@code WIRETYPE_} constants defined in
461    *          {@link WireFormat}.
462    */
463   static int getWireFormatForFieldType(final WireFormat.FieldType type,
464                                        boolean isPacked) {
465     if (isPacked) {
466       return WireFormat.WIRETYPE_LENGTH_DELIMITED;
467     } else {
468       return type.getWireType();
469     }
470   }
471
472   /**
473    * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another 
474    * {@link FieldSet}.
475    */
476   public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
477     for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
478       mergeFromField(other.fields.getArrayEntryAt(i));
479     }
480     for (final Map.Entry<FieldDescriptorType, Object> entry :
481              other.fields.getOverflowEntries()) {
482       mergeFromField(entry);
483     }
484   }
485
486   @SuppressWarnings({"unchecked", "rawtypes"})
487   private void mergeFromField(
488       final Map.Entry<FieldDescriptorType, Object> entry) {
489     final FieldDescriptorType descriptor = entry.getKey();
490     Object otherValue = entry.getValue();
491     if (otherValue instanceof LazyField) {
492       otherValue = ((LazyField) otherValue).getValue();
493     }
494
495     if (descriptor.isRepeated()) {
496       Object value = getField(descriptor);
497       if (value == null) {
498         // Our list is empty, but we still need to make a defensive copy of
499         // the other list since we don't know if the other FieldSet is still
500         // mutable.
501         fields.put(descriptor, new ArrayList((List) otherValue));
502       } else {
503         // Concatenate the lists.
504         ((List) value).addAll((List) otherValue);
505       }
506     } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
507       Object value = getField(descriptor);
508       if (value == null) {
509         fields.put(descriptor, otherValue);
510       } else {
511         // Merge the messages.
512         fields.put(
513             descriptor,
514             descriptor.internalMergeFrom(
515                 ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
516             .build());
517       }
518     } else {
519       fields.put(descriptor, otherValue);
520     }
521   }
522
523   // TODO(kenton):  Move static parsing and serialization methods into some
524   //   other class.  Probably WireFormat.
525
526   /**
527    * Read a field of any primitive type from a CodedInputStream.  Enums,
528    * groups, and embedded messages are not handled by this method.
529    *
530    * @param input The stream from which to read.
531    * @param type Declared type of the field.
532    * @return An object representing the field's value, of the exact
533    *         type which would be returned by
534    *         {@link Message#getField(Descriptors.FieldDescriptor)} for
535    *         this field.
536    */
537   public static Object readPrimitiveField(
538       CodedInputStream input,
539       final WireFormat.FieldType type) throws IOException {
540     switch (type) {
541       case DOUBLE  : return input.readDouble  ();
542       case FLOAT   : return input.readFloat   ();
543       case INT64   : return input.readInt64   ();
544       case UINT64  : return input.readUInt64  ();
545       case INT32   : return input.readInt32   ();
546       case FIXED64 : return input.readFixed64 ();
547       case FIXED32 : return input.readFixed32 ();
548       case BOOL    : return input.readBool    ();
549       case STRING  : return input.readString  ();
550       case BYTES   : return input.readBytes   ();
551       case UINT32  : return input.readUInt32  ();
552       case SFIXED32: return input.readSFixed32();
553       case SFIXED64: return input.readSFixed64();
554       case SINT32  : return input.readSInt32  ();
555       case SINT64  : return input.readSInt64  ();
556
557       case GROUP:
558         throw new IllegalArgumentException(
559           "readPrimitiveField() cannot handle nested groups.");
560       case MESSAGE:
561         throw new IllegalArgumentException(
562           "readPrimitiveField() cannot handle embedded messages.");
563       case ENUM:
564         // We don't handle enums because we don't know what to do if the
565         // value is not recognized.
566         throw new IllegalArgumentException(
567           "readPrimitiveField() cannot handle enums.");
568     }
569
570     throw new RuntimeException(
571       "There is no way to get here, but the compiler thinks otherwise.");
572   }
573
574   /** See {@link Message#writeTo(CodedOutputStream)}. */
575   public void writeTo(final CodedOutputStream output)
576                       throws IOException {
577     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
578       final Map.Entry<FieldDescriptorType, Object> entry =
579           fields.getArrayEntryAt(i);
580       writeField(entry.getKey(), entry.getValue(), output);
581     }
582     for (final Map.Entry<FieldDescriptorType, Object> entry :
583          fields.getOverflowEntries()) {
584       writeField(entry.getKey(), entry.getValue(), output);
585     }
586   }
587
588   /**
589    * Like {@link #writeTo} but uses MessageSet wire format.
590    */
591   public void writeMessageSetTo(final CodedOutputStream output)
592                                 throws IOException {
593     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
594       writeMessageSetTo(fields.getArrayEntryAt(i), output);
595     }
596     for (final Map.Entry<FieldDescriptorType, Object> entry :
597              fields.getOverflowEntries()) {
598       writeMessageSetTo(entry, output);
599     }
600   }
601
602   private void writeMessageSetTo(
603       final Map.Entry<FieldDescriptorType, Object> entry,
604       final CodedOutputStream output) throws IOException {
605     final FieldDescriptorType descriptor = entry.getKey();
606     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
607         !descriptor.isRepeated() && !descriptor.isPacked()) {
608       output.writeMessageSetExtension(entry.getKey().getNumber(),
609                                       (MessageLite) entry.getValue());
610     } else {
611       writeField(descriptor, entry.getValue(), output);
612     }
613   }
614
615   /**
616    * Write a single tag-value pair to the stream.
617    *
618    * @param output The output stream.
619    * @param type   The field's type.
620    * @param number The field's number.
621    * @param value  Object representing the field's value.  Must be of the exact
622    *               type which would be returned by
623    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
624    *               this field.
625    */
626   private static void writeElement(final CodedOutputStream output,
627                                    final WireFormat.FieldType type,
628                                    final int number,
629                                    final Object value) throws IOException {
630     // Special case for groups, which need a start and end tag; other fields
631     // can just use writeTag() and writeFieldNoTag().
632     if (type == WireFormat.FieldType.GROUP) {
633       output.writeGroup(number, (MessageLite) value);
634     } else {
635       output.writeTag(number, getWireFormatForFieldType(type, false));
636       writeElementNoTag(output, type, value);
637     }
638   }
639
640   /**
641    * Write a field of arbitrary type, without its tag, to the stream.
642    *
643    * @param output The output stream.
644    * @param type The field's type.
645    * @param value  Object representing the field's value.  Must be of the exact
646    *               type which would be returned by
647    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
648    *               this field.
649    */
650   private static void writeElementNoTag(
651       final CodedOutputStream output,
652       final WireFormat.FieldType type,
653       final Object value) throws IOException {
654     switch (type) {
655       case DOUBLE  : output.writeDoubleNoTag  ((Double     ) value); break;
656       case FLOAT   : output.writeFloatNoTag   ((Float      ) value); break;
657       case INT64   : output.writeInt64NoTag   ((Long       ) value); break;
658       case UINT64  : output.writeUInt64NoTag  ((Long       ) value); break;
659       case INT32   : output.writeInt32NoTag   ((Integer    ) value); break;
660       case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
661       case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
662       case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
663       case STRING  : output.writeStringNoTag  ((String     ) value); break;
664       case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
665       case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
666       case BYTES   : output.writeBytesNoTag   ((ByteString ) value); break;
667       case UINT32  : output.writeUInt32NoTag  ((Integer    ) value); break;
668       case SFIXED32: output.writeSFixed32NoTag((Integer    ) value); break;
669       case SFIXED64: output.writeSFixed64NoTag((Long       ) value); break;
670       case SINT32  : output.writeSInt32NoTag  ((Integer    ) value); break;
671       case SINT64  : output.writeSInt64NoTag  ((Long       ) value); break;
672
673       case ENUM:
674         output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
675         break;
676     }
677   }
678
679   /** Write a single field. */
680   public static void writeField(final FieldDescriptorLite<?> descriptor,
681                                 final Object value,
682                                 final CodedOutputStream output)
683                                 throws IOException {
684     WireFormat.FieldType type = descriptor.getLiteType();
685     int number = descriptor.getNumber();
686     if (descriptor.isRepeated()) {
687       final List<?> valueList = (List<?>)value;
688       if (descriptor.isPacked()) {
689         output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
690         // Compute the total data size so the length can be written.
691         int dataSize = 0;
692         for (final Object element : valueList) {
693           dataSize += computeElementSizeNoTag(type, element);
694         }
695         output.writeRawVarint32(dataSize);
696         // Write the data itself, without any tags.
697         for (final Object element : valueList) {
698           writeElementNoTag(output, type, element);
699         }
700       } else {
701         for (final Object element : valueList) {
702           writeElement(output, type, number, element);
703         }
704       }
705     } else {
706       if (value instanceof LazyField) {
707         writeElement(output, type, number, ((LazyField) value).getValue());
708       } else {
709         writeElement(output, type, number, value);
710       }
711     }
712   }
713
714   /**
715    * See {@link Message#getSerializedSize()}.  It's up to the caller to cache
716    * the resulting size if desired.
717    */
718   public int getSerializedSize() {
719     int size = 0;
720     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
721       final Map.Entry<FieldDescriptorType, Object> entry =
722           fields.getArrayEntryAt(i);
723       size += computeFieldSize(entry.getKey(), entry.getValue());
724     }
725     for (final Map.Entry<FieldDescriptorType, Object> entry :
726          fields.getOverflowEntries()) {
727       size += computeFieldSize(entry.getKey(), entry.getValue());
728     }
729     return size;
730   }
731
732   /**
733    * Like {@link #getSerializedSize} but uses MessageSet wire format.
734    */
735   public int getMessageSetSerializedSize() {
736     int size = 0;
737     for (int i = 0; i < fields.getNumArrayEntries(); i++) {
738       size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
739     }
740     for (final Map.Entry<FieldDescriptorType, Object> entry :
741              fields.getOverflowEntries()) {
742       size += getMessageSetSerializedSize(entry);
743     }
744     return size;
745   }
746
747   private int getMessageSetSerializedSize(
748       final Map.Entry<FieldDescriptorType, Object> entry) {
749     final FieldDescriptorType descriptor = entry.getKey();
750     Object value = entry.getValue();
751     if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE
752         && !descriptor.isRepeated() && !descriptor.isPacked()) {
753       if (value instanceof LazyField) {
754         return CodedOutputStream.computeLazyFieldMessageSetExtensionSize(
755             entry.getKey().getNumber(), (LazyField) value);
756       } else {
757         return CodedOutputStream.computeMessageSetExtensionSize(
758             entry.getKey().getNumber(), (MessageLite) value);
759       }
760     } else {
761       return computeFieldSize(descriptor, value);
762     }
763   }
764
765   /**
766    * Compute the number of bytes that would be needed to encode a
767    * single tag/value pair of arbitrary type.
768    *
769    * @param type   The field's type.
770    * @param number The field's number.
771    * @param value  Object representing the field's value.  Must be of the exact
772    *               type which would be returned by
773    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
774    *               this field.
775    */
776   private static int computeElementSize(
777       final WireFormat.FieldType type,
778       final int number, final Object value) {
779     int tagSize = CodedOutputStream.computeTagSize(number);
780     if (type == WireFormat.FieldType.GROUP) {
781       tagSize *= 2;
782     }
783     return tagSize + computeElementSizeNoTag(type, value);
784   }
785
786   /**
787    * Compute the number of bytes that would be needed to encode a
788    * particular value of arbitrary type, excluding tag.
789    *
790    * @param type   The field's type.
791    * @param value  Object representing the field's value.  Must be of the exact
792    *               type which would be returned by
793    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
794    *               this field.
795    */
796   private static int computeElementSizeNoTag(
797       final WireFormat.FieldType type, final Object value) {
798     switch (type) {
799       // Note:  Minor violation of 80-char limit rule here because this would
800       //   actually be harder to read if we wrapped the lines.
801       case DOUBLE  : return CodedOutputStream.computeDoubleSizeNoTag  ((Double     )value);
802       case FLOAT   : return CodedOutputStream.computeFloatSizeNoTag   ((Float      )value);
803       case INT64   : return CodedOutputStream.computeInt64SizeNoTag   ((Long       )value);
804       case UINT64  : return CodedOutputStream.computeUInt64SizeNoTag  ((Long       )value);
805       case INT32   : return CodedOutputStream.computeInt32SizeNoTag   ((Integer    )value);
806       case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
807       case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
808       case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
809       case STRING  : return CodedOutputStream.computeStringSizeNoTag  ((String     )value);
810       case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
811       case BYTES   : return CodedOutputStream.computeBytesSizeNoTag   ((ByteString )value);
812       case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
813       case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
814       case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
815       case SINT32  : return CodedOutputStream.computeSInt32SizeNoTag  ((Integer    )value);
816       case SINT64  : return CodedOutputStream.computeSInt64SizeNoTag  ((Long       )value);
817
818       case MESSAGE:
819         if (value instanceof LazyField) {
820           return CodedOutputStream.computeLazyFieldSizeNoTag((LazyField) value);
821         } else {
822           return CodedOutputStream.computeMessageSizeNoTag((MessageLite) value);
823         }
824
825       case ENUM:
826         return CodedOutputStream.computeEnumSizeNoTag(
827             ((Internal.EnumLite) value).getNumber());
828     }
829
830     throw new RuntimeException(
831       "There is no way to get here, but the compiler thinks otherwise.");
832   }
833
834   /**
835    * Compute the number of bytes needed to encode a particular field.
836    */
837   public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
838                                      final Object value) {
839     WireFormat.FieldType type = descriptor.getLiteType();
840     int number = descriptor.getNumber();
841     if (descriptor.isRepeated()) {
842       if (descriptor.isPacked()) {
843         int dataSize = 0;
844         for (final Object element : (List<?>)value) {
845           dataSize += computeElementSizeNoTag(type, element);
846         }
847         return dataSize +
848             CodedOutputStream.computeTagSize(number) +
849             CodedOutputStream.computeRawVarint32Size(dataSize);
850       } else {
851         int size = 0;
852         for (final Object element : (List<?>)value) {
853           size += computeElementSize(type, number, element);
854         }
855         return size;
856       }
857     } else {
858       return computeElementSize(type, number, value);
859     }
860   }
861 }