~statik/ubuntu/maverick/protobuf/A

« back to all changes in this revision

Viewing changes to java/src/main/java/com/google/protobuf/FieldSet.java

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2010-02-11 11:13:19 UTC
  • mfrom: (2.2.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100211111319-zdn8hmw0gh8s4cf8
Tags: 2.2.0a-0.1ubuntu1
* Merge from Debian testing.
* Remaining Ubuntu changes:
  - Don't use python2.4.
* Ubuntu changes dropped:
  - Disable death tests on Itanium, fixed upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 
31
31
package com.google.protobuf;
32
32
 
33
 
import com.google.protobuf.Descriptors.Descriptor;
34
 
import com.google.protobuf.Descriptors.FieldDescriptor;
35
 
import com.google.protobuf.Descriptors.EnumValueDescriptor;
36
 
 
37
33
import java.util.ArrayList;
38
34
import java.util.Collections;
39
35
import java.util.Iterator;
40
36
import java.util.TreeMap;
41
37
import java.util.List;
42
38
import java.util.Map;
 
39
import java.io.IOException;
43
40
 
44
41
/**
45
42
 * A class which represents an arbitrary set of fields of some message type.
49
46
 *
50
47
 * @author kenton@google.com Kenton Varda
51
48
 */
52
 
final class FieldSet {
53
 
  private Map<FieldDescriptor, Object> fields;
 
49
final class FieldSet<FieldDescriptorType extends
 
50
      FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
 
51
  /**
 
52
   * Interface for a FieldDescriptor or lite extension descriptor.  This
 
53
   * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
 
54
   */
 
55
  public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
 
56
      extends Comparable<T> {
 
57
    int getNumber();
 
58
    WireFormat.FieldType getLiteType();
 
59
    WireFormat.JavaType getLiteJavaType();
 
60
    boolean isRepeated();
 
61
    boolean isPacked();
 
62
    Internal.EnumLiteMap<?> getEnumType();
 
63
 
 
64
    // If getLiteJavaType() == MESSAGE, this merges a message object of the
 
65
    // type into a builder of the type.  Returns {@code to}.
 
66
    MessageLite.Builder internalMergeFrom(
 
67
        MessageLite.Builder to, MessageLite from);
 
68
  }
 
69
 
 
70
  private Map<FieldDescriptorType, Object> fields;
54
71
 
55
72
  /** Construct a new FieldSet. */
56
73
  private FieldSet() {
57
74
    // Use a TreeMap because fields need to be in canonical order when
58
75
    // serializing.
59
 
    this.fields = new TreeMap<FieldDescriptor, Object>();
 
76
    // TODO(kenton):  Maybe use some sort of sparse array instead?  It would
 
77
    //   even make sense to store the first 16 or so tags in a flat array
 
78
    //   to make DynamicMessage faster.
 
79
    fields = new TreeMap<FieldDescriptorType, Object>();
60
80
  }
61
81
 
62
82
  /**
63
 
   * Construct a new FieldSet with the given map.  This is only used by
64
 
   * DEFAULT_INSTANCE, to pass in an immutable empty map.
 
83
   * Construct an empty FieldSet.  This is only used to initialize
 
84
   * DEFAULT_INSTANCE.
65
85
   */
66
 
  private FieldSet(Map<FieldDescriptor, Object> fields) {
67
 
    this.fields = fields;
 
86
  private FieldSet(final boolean dummy) {
 
87
    this.fields = Collections.emptyMap();
68
88
  }
69
89
 
70
90
  /** Construct a new FieldSet. */
71
 
  public static FieldSet newFieldSet() {
72
 
    return new FieldSet();
 
91
  public static <T extends FieldSet.FieldDescriptorLite<T>>
 
92
      FieldSet<T> newFieldSet() {
 
93
    return new FieldSet<T>();
73
94
  }
74
95
 
75
96
  /** Get an immutable empty FieldSet. */
76
 
  public static FieldSet emptySet() {
 
97
  @SuppressWarnings("unchecked")
 
98
  public static <T extends FieldSet.FieldDescriptorLite<T>>
 
99
      FieldSet<T> emptySet() {
77
100
    return DEFAULT_INSTANCE;
78
101
  }
79
 
  private static final FieldSet DEFAULT_INSTANCE =
80
 
    new FieldSet(Collections.<FieldDescriptor, Object>emptyMap());
 
102
  @SuppressWarnings("unchecked")
 
103
  private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
81
104
 
82
105
  /** Make this FieldSet immutable from this point forward. */
83
106
  @SuppressWarnings("unchecked")
84
107
  public void makeImmutable() {
85
 
    for (Map.Entry<FieldDescriptor, Object> entry: fields.entrySet()) {
 
108
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
109
         fields.entrySet()) {
86
110
      if (entry.getKey().isRepeated()) {
87
 
        List value = (List)entry.getValue();
88
 
        entry.setValue(Collections.unmodifiableList(value));
 
111
        final List value = (List)entry.getValue();
 
112
        fields.put(entry.getKey(), Collections.unmodifiableList(value));
89
113
      }
90
114
    }
91
115
    fields = Collections.unmodifiableMap(fields);
98
122
    fields.clear();
99
123
  }
100
124
 
101
 
  /** See {@link Message#getAllFields()}. */
102
 
  public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
 
125
  /**
 
126
   * Get a simple map containing all the fields.
 
127
   */
 
128
  public Map<FieldDescriptorType, Object> getAllFields() {
103
129
    return Collections.unmodifiableMap(fields);
104
130
  }
105
131
 
106
132
  /**
107
 
   * Get an interator to the field map.  This iterator should not be leaked
 
133
   * Get an iterator to the field map.  This iterator should not be leaked
108
134
   * out of the protobuf library as it is not protected from mutation.
109
135
   */
110
 
  public Iterator<Map.Entry<Descriptors.FieldDescriptor, Object>> iterator() {
 
136
  public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
111
137
    return fields.entrySet().iterator();
112
138
  }
113
139
 
114
 
  /** See {@link Message#hasField(Descriptors.FieldDescriptor)}. */
115
 
  public boolean hasField(Descriptors.FieldDescriptor field) {
116
 
    if (field.isRepeated()) {
 
140
  /**
 
141
   * Useful for implementing
 
142
   * {@link Message#hasField(Descriptors.FieldDescriptor)}.
 
143
   */
 
144
  public boolean hasField(final FieldDescriptorType descriptor) {
 
145
    if (descriptor.isRepeated()) {
117
146
      throw new IllegalArgumentException(
118
147
        "hasField() can only be called on non-repeated fields.");
119
148
    }
120
149
 
121
 
    return fields.containsKey(field);
122
 
  }
123
 
 
124
 
  /**
125
 
   * See {@link Message#getField(Descriptors.FieldDescriptor)}.  This method
126
 
   * returns {@code null} if the field is a singular message type and is not
127
 
   * set; in this case it is up to the caller to fetch the message's default
128
 
   * instance.
129
 
   */
130
 
  public Object getField(Descriptors.FieldDescriptor field) {
131
 
    Object result = fields.get(field);
132
 
    if (result == null) {
133
 
      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
134
 
        if (field.isRepeated()) {
135
 
          return Collections.emptyList();
136
 
        } else {
137
 
          return null;
138
 
        }
139
 
      } else {
140
 
        return field.getDefaultValue();
141
 
      }
142
 
    } else {
143
 
      return result;
144
 
    }
145
 
  }
146
 
 
147
 
  /** See {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}. */
 
150
    return fields.get(descriptor) != null;
 
151
  }
 
152
 
 
153
  /**
 
154
   * Useful for implementing
 
155
   * {@link Message#getField(Descriptors.FieldDescriptor)}.  This method
 
156
   * returns {@code null} if the field is not set; in this case it is up
 
157
   * to the caller to fetch the field's default value.
 
158
   */
 
159
  public Object getField(final FieldDescriptorType descriptor) {
 
160
    return fields.get(descriptor);
 
161
  }
 
162
 
 
163
  /**
 
164
   * Useful for implementing
 
165
   * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
 
166
   */
148
167
  @SuppressWarnings("unchecked")
149
 
  public void setField(Descriptors.FieldDescriptor field, Object value) {
150
 
    if (field.isRepeated()) {
 
168
  public void setField(final FieldDescriptorType descriptor,
 
169
                       Object value) {
 
170
    if (descriptor.isRepeated()) {
151
171
      if (!(value instanceof List)) {
152
172
        throw new IllegalArgumentException(
153
173
          "Wrong object type used with protocol message reflection.");
155
175
 
156
176
      // Wrap the contents in a new list so that the caller cannot change
157
177
      // the list's contents after setting it.
158
 
      List newList = new ArrayList();
 
178
      final List newList = new ArrayList();
159
179
      newList.addAll((List)value);
160
 
      for (Object element : newList) {
161
 
        verifyType(field, element);
 
180
      for (final Object element : newList) {
 
181
        verifyType(descriptor.getLiteType(), element);
162
182
      }
163
183
      value = newList;
164
184
    } else {
165
 
      verifyType(field, value);
166
 
    }
167
 
 
168
 
    fields.put(field, value);
169
 
  }
170
 
 
171
 
  /** See {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}. */
172
 
  public void clearField(Descriptors.FieldDescriptor field) {
173
 
    fields.remove(field);
174
 
  }
175
 
 
176
 
  /** See {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}. */
177
 
  public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
178
 
    if (!field.isRepeated()) {
179
 
      throw new IllegalArgumentException(
180
 
        "getRepeatedFieldCount() can only be called on repeated fields.");
181
 
    }
182
 
 
183
 
    return ((List)getField(field)).size();
184
 
  }
185
 
 
186
 
  /** See {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}. */
187
 
  public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) {
188
 
    if (!field.isRepeated()) {
189
 
      throw new IllegalArgumentException(
190
 
        "getRepeatedField() can only be called on repeated fields.");
191
 
    }
192
 
 
193
 
    return ((List)getField(field)).get(index);
194
 
  }
195
 
 
196
 
  /** See {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}. */
197
 
  @SuppressWarnings("unchecked")
198
 
  public void setRepeatedField(Descriptors.FieldDescriptor field, int index,
199
 
                               Object value) {
200
 
    if (!field.isRepeated()) {
201
 
      throw new IllegalArgumentException(
202
 
        "setRepeatedField() can only be called on repeated fields.");
203
 
    }
204
 
 
205
 
    verifyType(field, value);
206
 
 
207
 
    List list = (List)fields.get(field);
208
 
    if (list == null) {
209
 
      throw new IndexOutOfBoundsException();
210
 
    }
211
 
 
212
 
    list.set(index, value);
213
 
  }
214
 
 
215
 
  /** See {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}. */
216
 
  @SuppressWarnings("unchecked")
217
 
  public void addRepeatedField(Descriptors.FieldDescriptor field,
218
 
                               Object value) {
219
 
    if (!field.isRepeated()) {
220
 
      throw new IllegalArgumentException(
221
 
        "setRepeatedField() can only be called on repeated fields.");
222
 
    }
223
 
 
224
 
    verifyType(field, value);
225
 
 
226
 
    List list = (List)fields.get(field);
227
 
    if (list == null) {
 
185
      verifyType(descriptor.getLiteType(), value);
 
186
    }
 
187
 
 
188
    fields.put(descriptor, value);
 
189
  }
 
190
 
 
191
  /**
 
192
   * Useful for implementing
 
193
   * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
 
194
   */
 
195
  public void clearField(final FieldDescriptorType descriptor) {
 
196
    fields.remove(descriptor);
 
197
  }
 
198
 
 
199
  /**
 
200
   * Useful for implementing
 
201
   * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
 
202
   */
 
203
  public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
 
204
    if (!descriptor.isRepeated()) {
 
205
      throw new IllegalArgumentException(
 
206
        "getRepeatedField() can only be called on repeated fields.");
 
207
    }
 
208
 
 
209
    final Object value = fields.get(descriptor);
 
210
    if (value == null) {
 
211
      return 0;
 
212
    } else {
 
213
      return ((List) value).size();
 
214
    }
 
215
  }
 
216
 
 
217
  /**
 
218
   * Useful for implementing
 
219
   * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
 
220
   */
 
221
  public Object getRepeatedField(final FieldDescriptorType descriptor,
 
222
                                 final int index) {
 
223
    if (!descriptor.isRepeated()) {
 
224
      throw new IllegalArgumentException(
 
225
        "getRepeatedField() can only be called on repeated fields.");
 
226
    }
 
227
 
 
228
    final Object value = fields.get(descriptor);
 
229
 
 
230
    if (value == null) {
 
231
      throw new IndexOutOfBoundsException();
 
232
    } else {
 
233
      return ((List) value).get(index);
 
234
    }
 
235
  }
 
236
 
 
237
  /**
 
238
   * Useful for implementing
 
239
   * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
 
240
   */
 
241
  @SuppressWarnings("unchecked")
 
242
  public void setRepeatedField(final FieldDescriptorType descriptor,
 
243
                               final int index,
 
244
                               final Object value) {
 
245
    if (!descriptor.isRepeated()) {
 
246
      throw new IllegalArgumentException(
 
247
        "getRepeatedField() can only be called on repeated fields.");
 
248
    }
 
249
 
 
250
    final Object list = fields.get(descriptor);
 
251
    if (list == null) {
 
252
      throw new IndexOutOfBoundsException();
 
253
    }
 
254
 
 
255
    verifyType(descriptor.getLiteType(), value);
 
256
    ((List) list).set(index, value);
 
257
  }
 
258
 
 
259
  /**
 
260
   * Useful for implementing
 
261
   * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
 
262
   */
 
263
  @SuppressWarnings("unchecked")
 
264
  public void addRepeatedField(final FieldDescriptorType descriptor,
 
265
                               final Object value) {
 
266
    if (!descriptor.isRepeated()) {
 
267
      throw new IllegalArgumentException(
 
268
        "addRepeatedField() can only be called on repeated fields.");
 
269
    }
 
270
 
 
271
    verifyType(descriptor.getLiteType(), value);
 
272
 
 
273
    final Object existingValue = fields.get(descriptor);
 
274
    List list;
 
275
    if (existingValue == null) {
228
276
      list = new ArrayList();
229
 
      fields.put(field, list);
 
277
      fields.put(descriptor, list);
 
278
    } else {
 
279
      list = (List) existingValue;
230
280
    }
231
281
 
232
282
    list.add(value);
239
289
   *
240
290
   * @throws IllegalArgumentException The value is not of the right type.
241
291
   */
242
 
  private void verifyType(FieldDescriptor field, Object value) {
 
292
  private static void verifyType(final WireFormat.FieldType type,
 
293
                                 final Object value) {
 
294
    if (value == null) {
 
295
      throw new NullPointerException();
 
296
    }
 
297
 
243
298
    boolean isValid = false;
244
 
    switch (field.getJavaType()) {
 
299
    switch (type.getJavaType()) {
245
300
      case INT:          isValid = value instanceof Integer   ; break;
246
301
      case LONG:         isValid = value instanceof Long      ; break;
247
302
      case FLOAT:        isValid = value instanceof Float     ; break;
250
305
      case STRING:       isValid = value instanceof String    ; break;
251
306
      case BYTE_STRING:  isValid = value instanceof ByteString; break;
252
307
      case ENUM:
253
 
        isValid = value instanceof EnumValueDescriptor &&
254
 
          ((EnumValueDescriptor)value).getType() == field.getEnumType();
 
308
        // TODO(kenton):  Caller must do type checking here, I guess.
 
309
        isValid = value instanceof Internal.EnumLite;
255
310
        break;
256
311
      case MESSAGE:
257
 
        isValid = value instanceof Message &&
258
 
          ((Message)value).getDescriptorForType() == field.getMessageType();
 
312
        // TODO(kenton):  Caller must do type checking here, I guess.
 
313
        isValid = value instanceof MessageLite;
259
314
        break;
260
315
    }
261
316
 
262
317
    if (!isValid) {
263
 
      // When chaining calls to setField(), it can be hard to tell from
264
 
      // the stack trace which exact call failed, since the whole chain is
265
 
      // considered one line of code.  So, let's make sure to include the
266
 
      // field name and other useful info in the exception.
 
318
      // TODO(kenton):  When chaining calls to setField(), it can be hard to
 
319
      //   tell from the stack trace which exact call failed, since the whole
 
320
      //   chain is considered one line of code.  It would be nice to print
 
321
      //   more information here, e.g. naming the field.  We used to do that.
 
322
      //   But we can't now that FieldSet doesn't use descriptors.  Maybe this
 
323
      //   isn't a big deal, though, since it would only really apply when using
 
324
      //   reflection and generally people don't chain reflection setters.
267
325
      throw new IllegalArgumentException(
268
 
        "Wrong object type used with protocol message reflection.  " +
269
 
        "Message type \"" + field.getContainingType().getFullName() +
270
 
        "\", field \"" +
271
 
        (field.isExtension() ? field.getFullName() : field.getName()) +
272
 
        "\", value was type \"" + value.getClass().getName() + "\".");
 
326
        "Wrong object type used with protocol message reflection.");
273
327
    }
274
328
  }
275
329
 
284
338
   */
285
339
  @SuppressWarnings("unchecked")
286
340
  public boolean isInitialized() {
287
 
    for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
288
 
      FieldDescriptor field = entry.getKey();
289
 
      if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
290
 
        if (field.isRepeated()) {
291
 
          for (Message element : (List<Message>) entry.getValue()) {
 
341
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
342
         fields.entrySet()) {
 
343
      final FieldDescriptorType descriptor = entry.getKey();
 
344
      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
 
345
        if (descriptor.isRepeated()) {
 
346
          for (final MessageLite element:
 
347
               (List<MessageLite>) entry.getValue()) {
292
348
            if (!element.isInitialized()) {
293
349
              return false;
294
350
            }
295
351
          }
296
352
        } else {
297
 
          if (!((Message) entry.getValue()).isInitialized()) {
 
353
          if (!((MessageLite) entry.getValue()).isInitialized()) {
298
354
            return false;
299
355
          }
300
356
        }
305
361
  }
306
362
 
307
363
  /**
308
 
   * Like {@link #isInitialized()}, but also checks for the presence of
309
 
   * all required fields in the given type.
 
364
   * Given a field type, return the wire type.
 
365
   *
 
366
   * @returns One of the {@code WIRETYPE_} constants defined in
 
367
   *          {@link WireFormat}.
310
368
   */
311
 
  @SuppressWarnings("unchecked")
312
 
  public boolean isInitialized(Descriptor type) {
313
 
    // Check that all required fields are present.
314
 
    for (FieldDescriptor field : type.getFields()) {
315
 
      if (field.isRequired()) {
316
 
        if (!hasField(field)) {
317
 
          return false;
318
 
        }
319
 
      }
320
 
    }
321
 
 
322
 
    // Check that embedded messages are initialized.
323
 
    return isInitialized();
324
 
  }
325
 
 
326
 
  /** See {@link Message.Builder#mergeFrom(Message)}. */
327
 
  @SuppressWarnings("unchecked")
328
 
  public void mergeFrom(Message other) {
329
 
    // Note:  We don't attempt to verify that other's fields have valid
330
 
    //   types.  Doing so would be a losing battle.  We'd have to verify
331
 
    //   all sub-messages as well, and we'd have to make copies of all of
332
 
    //   them to insure that they don't change after verification (since
333
 
    //   the Message interface itself cannot enforce immutability of
334
 
    //   implementations).
335
 
    // TODO(kenton):  Provide a function somewhere called makeDeepCopy()
336
 
    //   which allows people to make secure deep copies of messages.
337
 
 
338
 
    for (Map.Entry<FieldDescriptor, Object> entry :
339
 
         other.getAllFields().entrySet()) {
340
 
      FieldDescriptor field = entry.getKey();
341
 
      if (field.isRepeated()) {
342
 
        List existingValue = (List)fields.get(field);
343
 
        if (existingValue == null) {
344
 
          existingValue = new ArrayList();
345
 
          fields.put(field, existingValue);
346
 
        }
347
 
        existingValue.addAll((List)entry.getValue());
348
 
      } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
349
 
        Message existingValue = (Message)fields.get(field);
350
 
        if (existingValue == null) {
351
 
          setField(field, entry.getValue());
352
 
        } else {
353
 
          setField(field,
354
 
            existingValue.toBuilder()
355
 
              .mergeFrom((Message)entry.getValue())
356
 
              .build());
357
 
        }
358
 
      } else {
359
 
        setField(field, entry.getValue());
360
 
      }
 
369
  static int getWireFormatForFieldType(final WireFormat.FieldType type,
 
370
                                       boolean isPacked) {
 
371
    if (isPacked) {
 
372
      return WireFormat.WIRETYPE_LENGTH_DELIMITED;
 
373
    } else {
 
374
      return type.getWireType();
361
375
    }
362
376
  }
363
377
 
365
379
   * Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
366
380
   */
367
381
  @SuppressWarnings("unchecked")
368
 
  public void mergeFrom(FieldSet other) {
369
 
    for (Map.Entry<FieldDescriptor, Object> entry : other.fields.entrySet()) {
370
 
      FieldDescriptor field = entry.getKey();
371
 
      Object value = entry.getValue();
372
 
 
373
 
      if (field.isRepeated()) {
374
 
        List existingValue = (List)fields.get(field);
375
 
        if (existingValue == null) {
376
 
          existingValue = new ArrayList();
377
 
          fields.put(field, existingValue);
378
 
        }
379
 
        existingValue.addAll((List)value);
380
 
      } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
381
 
        Message existingValue = (Message)fields.get(field);
382
 
        if (existingValue == null) {
383
 
          setField(field, value);
384
 
        } else {
385
 
          setField(field,
386
 
            existingValue.toBuilder()
387
 
              .mergeFrom((Message)value)
388
 
              .build());
389
 
        }
390
 
      } else {
391
 
        setField(field, value);
392
 
      }
393
 
    }
394
 
  }
395
 
 
396
 
  // TODO(kenton):  Move parsing code into AbstractMessage, since it no longer
397
 
  //   uses any special knowledge from FieldSet.
398
 
 
399
 
  /**
400
 
   * See {@link Message.Builder#mergeFrom(CodedInputStream)}.
401
 
   * @param builder The {@code Builder} for the target message.
402
 
   */
403
 
  public static void mergeFrom(CodedInputStream input,
404
 
                               UnknownFieldSet.Builder unknownFields,
405
 
                               ExtensionRegistry extensionRegistry,
406
 
                               Message.Builder builder)
407
 
                               throws java.io.IOException {
408
 
    while (true) {
409
 
      int tag = input.readTag();
410
 
      if (tag == 0) {
411
 
        break;
412
 
      }
413
 
 
414
 
      if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
415
 
                          builder, tag)) {
416
 
        // end group tag
417
 
        break;
418
 
      }
419
 
    }
420
 
  }
421
 
 
422
 
  /**
423
 
   * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
424
 
   * ExtensionRegistry, Message.Builder)}, but parses a single field.
425
 
   * @param tag The tag, which should have already been read.
426
 
   * @return {@code true} unless the tag is an end-group tag.
427
 
   */
428
 
  @SuppressWarnings("unchecked")
429
 
  public static boolean mergeFieldFrom(
430
 
      CodedInputStream input,
431
 
      UnknownFieldSet.Builder unknownFields,
432
 
      ExtensionRegistry extensionRegistry,
433
 
      Message.Builder builder,
434
 
      int tag) throws java.io.IOException {
435
 
    Descriptor type = builder.getDescriptorForType();
436
 
 
437
 
    if (type.getOptions().getMessageSetWireFormat() &&
438
 
        tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
439
 
      mergeMessageSetExtensionFromCodedStream(
440
 
        input, unknownFields, extensionRegistry, builder);
441
 
      return true;
442
 
    }
443
 
 
444
 
    int wireType = WireFormat.getTagWireType(tag);
445
 
    int fieldNumber = WireFormat.getTagFieldNumber(tag);
446
 
 
447
 
    FieldDescriptor field;
448
 
    Message defaultInstance = null;
449
 
 
450
 
    if (type.isExtensionNumber(fieldNumber)) {
451
 
      ExtensionRegistry.ExtensionInfo extension =
452
 
        extensionRegistry.findExtensionByNumber(type, fieldNumber);
453
 
      if (extension == null) {
454
 
        field = null;
455
 
      } else {
456
 
        field = extension.descriptor;
457
 
        defaultInstance = extension.defaultInstance;
458
 
      }
459
 
    } else {
460
 
      field = type.findFieldByNumber(fieldNumber);
461
 
    }
462
 
 
463
 
    if (field == null ||
464
 
        wireType != WireFormat.getWireFormatForField(field)) {
465
 
      // Unknown field or wrong wire type.  Skip.
466
 
      return unknownFields.mergeFieldFrom(tag, input);
467
 
    } else {
468
 
      if (field.getOptions().getPacked()) {
469
 
        int length = input.readRawVarint32();
470
 
        int limit = input.pushLimit(length);
471
 
        if (field.getType() == FieldDescriptor.Type.ENUM) {
472
 
          while (input.getBytesUntilLimit() > 0) {
473
 
            int rawValue = input.readEnum();
474
 
            Object value = field.getEnumType().findValueByNumber(rawValue);
475
 
            if (value == null) {
476
 
              // If the number isn't recognized as a valid value for this
477
 
              // enum, drop it (don't even add it to unknownFields).
478
 
              return true;
479
 
            }
480
 
            builder.addRepeatedField(field, value);
481
 
          }
482
 
        } else {
483
 
          while (input.getBytesUntilLimit() > 0) {
484
 
            Object value = input.readPrimitiveField(field.getType());
485
 
            builder.addRepeatedField(field, value);
486
 
          }
487
 
        }
488
 
        input.popLimit(limit);
489
 
      } else {
490
 
        Object value;
491
 
        switch (field.getType()) {
492
 
          case GROUP: {
493
 
            Message.Builder subBuilder;
494
 
            if (defaultInstance != null) {
495
 
              subBuilder = defaultInstance.newBuilderForType();
496
 
            } else {
497
 
              subBuilder = builder.newBuilderForField(field);
498
 
            }
499
 
            if (!field.isRepeated()) {
500
 
              subBuilder.mergeFrom((Message) builder.getField(field));
501
 
            }
502
 
            input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
503
 
            value = subBuilder.build();
504
 
            break;
505
 
          }
506
 
          case MESSAGE: {
507
 
            Message.Builder subBuilder;
508
 
            if (defaultInstance != null) {
509
 
              subBuilder = defaultInstance.newBuilderForType();
510
 
            } else {
511
 
              subBuilder = builder.newBuilderForField(field);
512
 
            }
513
 
            if (!field.isRepeated()) {
514
 
              subBuilder.mergeFrom((Message) builder.getField(field));
515
 
            }
516
 
            input.readMessage(subBuilder, extensionRegistry);
517
 
            value = subBuilder.build();
518
 
            break;
519
 
          }
520
 
          case ENUM: {
521
 
            int rawValue = input.readEnum();
522
 
            value = field.getEnumType().findValueByNumber(rawValue);
523
 
            // If the number isn't recognized as a valid value for this enum,
524
 
            // drop it.
525
 
            if (value == null) {
526
 
              unknownFields.mergeVarintField(fieldNumber, rawValue);
527
 
              return true;
528
 
            }
529
 
            break;
530
 
          }
531
 
          default:
532
 
            value = input.readPrimitiveField(field.getType());
533
 
            break;
534
 
        }
535
 
 
536
 
        if (field.isRepeated()) {
537
 
          builder.addRepeatedField(field, value);
538
 
        } else {
539
 
          builder.setField(field, value);
540
 
        }
541
 
      }
542
 
    }
543
 
 
544
 
    return true;
545
 
  }
546
 
 
547
 
  /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
548
 
  private static void mergeMessageSetExtensionFromCodedStream(
549
 
      CodedInputStream input,
550
 
      UnknownFieldSet.Builder unknownFields,
551
 
      ExtensionRegistry extensionRegistry,
552
 
      Message.Builder builder) throws java.io.IOException {
553
 
    Descriptor type = builder.getDescriptorForType();
554
 
 
555
 
    // The wire format for MessageSet is:
556
 
    //   message MessageSet {
557
 
    //     repeated group Item = 1 {
558
 
    //       required int32 typeId = 2;
559
 
    //       required bytes message = 3;
560
 
    //     }
561
 
    //   }
562
 
    // "typeId" is the extension's field number.  The extension can only be
563
 
    // a message type, where "message" contains the encoded bytes of that
564
 
    // message.
565
 
    //
566
 
    // In practice, we will probably never see a MessageSet item in which
567
 
    // the message appears before the type ID, or where either field does not
568
 
    // appear exactly once.  However, in theory such cases are valid, so we
569
 
    // should be prepared to accept them.
570
 
 
571
 
    int typeId = 0;
572
 
    ByteString rawBytes = null;  // If we encounter "message" before "typeId"
573
 
    Message.Builder subBuilder = null;
574
 
    FieldDescriptor field = null;
575
 
 
576
 
    while (true) {
577
 
      int tag = input.readTag();
578
 
      if (tag == 0) {
579
 
        break;
580
 
      }
581
 
 
582
 
      if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
583
 
        typeId = input.readUInt32();
584
 
        // Zero is not a valid type ID.
585
 
        if (typeId != 0) {
586
 
          ExtensionRegistry.ExtensionInfo extension =
587
 
            extensionRegistry.findExtensionByNumber(type, typeId);
588
 
          if (extension != null) {
589
 
            field = extension.descriptor;
590
 
            subBuilder = extension.defaultInstance.newBuilderForType();
591
 
            Message originalMessage = (Message)builder.getField(field);
592
 
            if (originalMessage != null) {
593
 
              subBuilder.mergeFrom(originalMessage);
594
 
            }
595
 
            if (rawBytes != null) {
596
 
              // We already encountered the message.  Parse it now.
597
 
              subBuilder.mergeFrom(
598
 
                CodedInputStream.newInstance(rawBytes.newInput()));
599
 
              rawBytes = null;
600
 
            }
601
 
          } else {
602
 
            // Unknown extension number.  If we already saw data, put it
603
 
            // in rawBytes.
604
 
            if (rawBytes != null) {
605
 
              unknownFields.mergeField(typeId,
606
 
                UnknownFieldSet.Field.newBuilder()
607
 
                  .addLengthDelimited(rawBytes)
608
 
                  .build());
609
 
              rawBytes = null;
610
 
            }
611
 
          }
612
 
        }
613
 
      } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
614
 
        if (typeId == 0) {
615
 
          // We haven't seen a type ID yet, so we have to store the raw bytes
616
 
          // for now.
617
 
          rawBytes = input.readBytes();
618
 
        } else if (subBuilder == null) {
619
 
          // We don't know how to parse this.  Ignore it.
620
 
          unknownFields.mergeField(typeId,
621
 
            UnknownFieldSet.Field.newBuilder()
622
 
              .addLengthDelimited(input.readBytes())
623
 
              .build());
624
 
        } else {
625
 
          // We already know the type, so we can parse directly from the input
626
 
          // with no copying.  Hooray!
627
 
          input.readMessage(subBuilder, extensionRegistry);
628
 
        }
629
 
      } else {
630
 
        // Unknown tag.  Skip it.
631
 
        if (!input.skipField(tag)) {
632
 
          break;  // end of group
633
 
        }
634
 
      }
635
 
    }
636
 
 
637
 
    input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
638
 
 
639
 
    if (subBuilder != null) {
640
 
      builder.setField(field, subBuilder.build());
641
 
    }
 
382
  public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
 
383
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
384
         other.fields.entrySet()) {
 
385
      final FieldDescriptorType descriptor = entry.getKey();
 
386
      final Object otherValue = entry.getValue();
 
387
 
 
388
      if (descriptor.isRepeated()) {
 
389
        Object value = fields.get(descriptor);
 
390
        if (value == null) {
 
391
          // Our list is empty, but we still need to make a defensive copy of
 
392
          // the other list since we don't know if the other FieldSet is still
 
393
          // mutable.
 
394
          fields.put(descriptor, new ArrayList((List) otherValue));
 
395
        } else {
 
396
          // Concatenate the lists.
 
397
          ((List) value).addAll((List) otherValue);
 
398
        }
 
399
      } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
 
400
        Object value = fields.get(descriptor);
 
401
        if (value == null) {
 
402
          fields.put(descriptor, otherValue);
 
403
        } else {
 
404
          // Merge the messages.
 
405
          fields.put(descriptor,
 
406
              descriptor.internalMergeFrom(
 
407
                ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
 
408
              .build());
 
409
        }
 
410
 
 
411
      } else {
 
412
        fields.put(descriptor, otherValue);
 
413
      }
 
414
    }
 
415
  }
 
416
 
 
417
  // TODO(kenton):  Move static parsing and serialization methods into some
 
418
  //   other class.  Probably WireFormat.
 
419
 
 
420
  /**
 
421
   * Read a field of any primitive type from a CodedInputStream.  Enums,
 
422
   * groups, and embedded messages are not handled by this method.
 
423
   *
 
424
   * @param input The stream from which to read.
 
425
   * @param type Declared type of the field.
 
426
   * @return An object representing the field's value, of the exact
 
427
   *         type which would be returned by
 
428
   *         {@link Message#getField(Descriptors.FieldDescriptor)} for
 
429
   *         this field.
 
430
   */
 
431
  public static Object readPrimitiveField(
 
432
      CodedInputStream input,
 
433
      final WireFormat.FieldType type) throws IOException {
 
434
    switch (type) {
 
435
      case DOUBLE  : return input.readDouble  ();
 
436
      case FLOAT   : return input.readFloat   ();
 
437
      case INT64   : return input.readInt64   ();
 
438
      case UINT64  : return input.readUInt64  ();
 
439
      case INT32   : return input.readInt32   ();
 
440
      case FIXED64 : return input.readFixed64 ();
 
441
      case FIXED32 : return input.readFixed32 ();
 
442
      case BOOL    : return input.readBool    ();
 
443
      case STRING  : return input.readString  ();
 
444
      case BYTES   : return input.readBytes   ();
 
445
      case UINT32  : return input.readUInt32  ();
 
446
      case SFIXED32: return input.readSFixed32();
 
447
      case SFIXED64: return input.readSFixed64();
 
448
      case SINT32  : return input.readSInt32  ();
 
449
      case SINT64  : return input.readSInt64  ();
 
450
 
 
451
      case GROUP:
 
452
        throw new IllegalArgumentException(
 
453
          "readPrimitiveField() cannot handle nested groups.");
 
454
      case MESSAGE:
 
455
        throw new IllegalArgumentException(
 
456
          "readPrimitiveField() cannot handle embedded messages.");
 
457
      case ENUM:
 
458
        // We don't handle enums because we don't know what to do if the
 
459
        // value is not recognized.
 
460
        throw new IllegalArgumentException(
 
461
          "readPrimitiveField() cannot handle enums.");
 
462
    }
 
463
 
 
464
    throw new RuntimeException(
 
465
      "There is no way to get here, but the compiler thinks otherwise.");
642
466
  }
643
467
 
644
468
  /** See {@link Message#writeTo(CodedOutputStream)}. */
645
 
  public void writeTo(CodedOutputStream output)
646
 
                      throws java.io.IOException {
647
 
    for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
 
469
  public void writeTo(final CodedOutputStream output)
 
470
                      throws IOException {
 
471
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
472
         fields.entrySet()) {
648
473
      writeField(entry.getKey(), entry.getValue(), output);
649
474
    }
650
475
  }
651
476
 
 
477
  /**
 
478
   * Like {@link #writeTo} but uses MessageSet wire format.
 
479
   */
 
480
  public void writeMessageSetTo(final CodedOutputStream output)
 
481
                                throws IOException {
 
482
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
483
         fields.entrySet()) {
 
484
      final FieldDescriptorType descriptor = entry.getKey();
 
485
      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
 
486
          !descriptor.isRepeated() && !descriptor.isPacked()) {
 
487
        output.writeMessageSetExtension(entry.getKey().getNumber(),
 
488
                                        (MessageLite) entry.getValue());
 
489
      } else {
 
490
        writeField(descriptor, entry.getValue(), output);
 
491
      }
 
492
    }
 
493
  }
 
494
 
 
495
  /**
 
496
   * Write a single tag-value pair to the stream.
 
497
   *
 
498
   * @param output The output stream.
 
499
   * @param type   The field's type.
 
500
   * @param number The field's number.
 
501
   * @param value  Object representing the field's value.  Must be of the exact
 
502
   *               type which would be returned by
 
503
   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
 
504
   *               this field.
 
505
   */
 
506
  private static void writeElement(final CodedOutputStream output,
 
507
                                   final WireFormat.FieldType type,
 
508
                                   final int number,
 
509
                                   final Object value) throws IOException {
 
510
    // Special case for groups, which need a start and end tag; other fields
 
511
    // can just use writeTag() and writeFieldNoTag().
 
512
    if (type == WireFormat.FieldType.GROUP) {
 
513
      output.writeGroup(number, (MessageLite) value);
 
514
    } else {
 
515
      output.writeTag(number, getWireFormatForFieldType(type, false));
 
516
      writeElementNoTag(output, type, value);
 
517
    }
 
518
  }
 
519
 
 
520
  /**
 
521
   * Write a field of arbitrary type, without its tag, to the stream.
 
522
   *
 
523
   * @param output The output stream.
 
524
   * @param type The field's type.
 
525
   * @param value  Object representing the field's value.  Must be of the exact
 
526
   *               type which would be returned by
 
527
   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
 
528
   *               this field.
 
529
   */
 
530
  private static void writeElementNoTag(
 
531
      final CodedOutputStream output,
 
532
      final WireFormat.FieldType type,
 
533
      final Object value) throws IOException {
 
534
    switch (type) {
 
535
      case DOUBLE  : output.writeDoubleNoTag  ((Double     ) value); break;
 
536
      case FLOAT   : output.writeFloatNoTag   ((Float      ) value); break;
 
537
      case INT64   : output.writeInt64NoTag   ((Long       ) value); break;
 
538
      case UINT64  : output.writeUInt64NoTag  ((Long       ) value); break;
 
539
      case INT32   : output.writeInt32NoTag   ((Integer    ) value); break;
 
540
      case FIXED64 : output.writeFixed64NoTag ((Long       ) value); break;
 
541
      case FIXED32 : output.writeFixed32NoTag ((Integer    ) value); break;
 
542
      case BOOL    : output.writeBoolNoTag    ((Boolean    ) value); break;
 
543
      case STRING  : output.writeStringNoTag  ((String     ) value); break;
 
544
      case GROUP   : output.writeGroupNoTag   ((MessageLite) value); break;
 
545
      case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
 
546
      case BYTES   : output.writeBytesNoTag   ((ByteString ) value); break;
 
547
      case UINT32  : output.writeUInt32NoTag  ((Integer    ) value); break;
 
548
      case SFIXED32: output.writeSFixed32NoTag((Integer    ) value); break;
 
549
      case SFIXED64: output.writeSFixed64NoTag((Long       ) value); break;
 
550
      case SINT32  : output.writeSInt32NoTag  ((Integer    ) value); break;
 
551
      case SINT64  : output.writeSInt64NoTag  ((Long       ) value); break;
 
552
 
 
553
      case ENUM:
 
554
        output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
 
555
        break;
 
556
    }
 
557
  }
 
558
 
652
559
  /** Write a single field. */
653
 
  public void writeField(FieldDescriptor field, Object value,
654
 
                         CodedOutputStream output) throws java.io.IOException {
655
 
    if (field.isExtension() &&
656
 
        field.getContainingType().getOptions().getMessageSetWireFormat()) {
657
 
      output.writeMessageSetExtension(field.getNumber(), (Message)value);
658
 
    } else {
659
 
      if (field.isRepeated()) {
660
 
        List valueList = (List)value;
661
 
        if (field.getOptions().getPacked()) {
662
 
          output.writeTag(field.getNumber(),
663
 
                          WireFormat.WIRETYPE_LENGTH_DELIMITED);
664
 
          // Compute the total data size so the length can be written.
665
 
          int dataSize = 0;
666
 
          for (Object element : valueList) {
667
 
            dataSize += output.computeFieldSizeNoTag(field.getType(), element);
668
 
          }
669
 
          output.writeRawVarint32(dataSize);
670
 
          // Write the data itself, without any tags.
671
 
          for (Object element : valueList) {
672
 
            output.writeFieldNoTag(field.getType(), element);
673
 
          }
674
 
        } else {
675
 
          for (Object element : valueList) {
676
 
            output.writeField(field.getType(), field.getNumber(), element);
677
 
          }
 
560
  public static void writeField(final FieldDescriptorLite<?> descriptor,
 
561
                                final Object value,
 
562
                                final CodedOutputStream output)
 
563
                                throws IOException {
 
564
    WireFormat.FieldType type = descriptor.getLiteType();
 
565
    int number = descriptor.getNumber();
 
566
    if (descriptor.isRepeated()) {
 
567
      final List valueList = (List)value;
 
568
      if (descriptor.isPacked()) {
 
569
        output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
 
570
        // Compute the total data size so the length can be written.
 
571
        int dataSize = 0;
 
572
        for (final Object element : valueList) {
 
573
          dataSize += computeElementSizeNoTag(type, element);
 
574
        }
 
575
        output.writeRawVarint32(dataSize);
 
576
        // Write the data itself, without any tags.
 
577
        for (final Object element : valueList) {
 
578
          writeElementNoTag(output, type, element);
678
579
        }
679
580
      } else {
680
 
        output.writeField(field.getType(), field.getNumber(), value);
 
581
        for (final Object element : valueList) {
 
582
          writeElement(output, type, number, element);
 
583
        }
681
584
      }
 
585
    } else {
 
586
      writeElement(output, type, number, value);
682
587
    }
683
588
  }
684
589
 
688
593
   */
689
594
  public int getSerializedSize() {
690
595
    int size = 0;
691
 
    for (Map.Entry<FieldDescriptor, Object> entry : fields.entrySet()) {
692
 
      FieldDescriptor field = entry.getKey();
693
 
      Object value = entry.getValue();
 
596
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
597
         fields.entrySet()) {
 
598
      size += computeFieldSize(entry.getKey(), entry.getValue());
 
599
    }
 
600
    return size;
 
601
  }
694
602
 
695
 
      if (field.isExtension() &&
696
 
          field.getContainingType().getOptions().getMessageSetWireFormat()) {
 
603
  /**
 
604
   * Like {@link #getSerializedSize} but uses MessageSet wire format.
 
605
   */
 
606
  public int getMessageSetSerializedSize() {
 
607
    int size = 0;
 
608
    for (final Map.Entry<FieldDescriptorType, Object> entry:
 
609
         fields.entrySet()) {
 
610
      final FieldDescriptorType descriptor = entry.getKey();
 
611
      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
 
612
          !descriptor.isRepeated() && !descriptor.isPacked()) {
697
613
        size += CodedOutputStream.computeMessageSetExtensionSize(
698
 
          field.getNumber(), (Message) value);
 
614
                  entry.getKey().getNumber(), (MessageLite) entry.getValue());
699
615
      } else {
700
 
        if (field.isRepeated()) {
701
 
          if (field.getOptions().getPacked()) {
702
 
            int dataSize = 0;
703
 
            for (Object element : (List)value) {
704
 
              dataSize += CodedOutputStream.computeFieldSizeNoTag(
705
 
                  field.getType(), element);
706
 
            }
707
 
            size += dataSize +
708
 
                CodedOutputStream.computeTagSize(field.getNumber()) +
709
 
                CodedOutputStream.computeRawVarint32Size(dataSize);
710
 
          } else {
711
 
            for (Object element : (List)value) {
712
 
              size += CodedOutputStream.computeFieldSize(
713
 
                  field.getType(), field.getNumber(), element);
714
 
            }
715
 
          }
716
 
        } else {
717
 
          size += CodedOutputStream.computeFieldSize(
718
 
            field.getType(), field.getNumber(), value);
719
 
        }
 
616
        size += computeFieldSize(descriptor, entry.getValue());
720
617
      }
721
618
    }
722
619
    return size;
723
620
  }
 
621
 
 
622
  /**
 
623
   * Compute the number of bytes that would be needed to encode a
 
624
   * single tag/value pair of arbitrary type.
 
625
   *
 
626
   * @param type   The field's type.
 
627
   * @param number The field's number.
 
628
   * @param value  Object representing the field's value.  Must be of the exact
 
629
   *               type which would be returned by
 
630
   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
 
631
   *               this field.
 
632
   */
 
633
  private static int computeElementSize(
 
634
      final WireFormat.FieldType type,
 
635
      final int number, final Object value) {
 
636
    int tagSize = CodedOutputStream.computeTagSize(number);
 
637
    if (type == WireFormat.FieldType.GROUP) {
 
638
      tagSize *= 2;
 
639
    }
 
640
    return tagSize + computeElementSizeNoTag(type, value);
 
641
  }
 
642
 
 
643
  /**
 
644
   * Compute the number of bytes that would be needed to encode a
 
645
   * particular value of arbitrary type, excluding tag.
 
646
   *
 
647
   * @param type   The field's type.
 
648
   * @param value  Object representing the field's value.  Must be of the exact
 
649
   *               type which would be returned by
 
650
   *               {@link Message#getField(Descriptors.FieldDescriptor)} for
 
651
   *               this field.
 
652
   */
 
653
  private static int computeElementSizeNoTag(
 
654
      final WireFormat.FieldType type, final Object value) {
 
655
    switch (type) {
 
656
      // Note:  Minor violation of 80-char limit rule here because this would
 
657
      //   actually be harder to read if we wrapped the lines.
 
658
      case DOUBLE  : return CodedOutputStream.computeDoubleSizeNoTag  ((Double     )value);
 
659
      case FLOAT   : return CodedOutputStream.computeFloatSizeNoTag   ((Float      )value);
 
660
      case INT64   : return CodedOutputStream.computeInt64SizeNoTag   ((Long       )value);
 
661
      case UINT64  : return CodedOutputStream.computeUInt64SizeNoTag  ((Long       )value);
 
662
      case INT32   : return CodedOutputStream.computeInt32SizeNoTag   ((Integer    )value);
 
663
      case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long       )value);
 
664
      case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer    )value);
 
665
      case BOOL    : return CodedOutputStream.computeBoolSizeNoTag    ((Boolean    )value);
 
666
      case STRING  : return CodedOutputStream.computeStringSizeNoTag  ((String     )value);
 
667
      case GROUP   : return CodedOutputStream.computeGroupSizeNoTag   ((MessageLite)value);
 
668
      case MESSAGE : return CodedOutputStream.computeMessageSizeNoTag ((MessageLite)value);
 
669
      case BYTES   : return CodedOutputStream.computeBytesSizeNoTag   ((ByteString )value);
 
670
      case UINT32  : return CodedOutputStream.computeUInt32SizeNoTag  ((Integer    )value);
 
671
      case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer    )value);
 
672
      case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long       )value);
 
673
      case SINT32  : return CodedOutputStream.computeSInt32SizeNoTag  ((Integer    )value);
 
674
      case SINT64  : return CodedOutputStream.computeSInt64SizeNoTag  ((Long       )value);
 
675
 
 
676
      case ENUM:
 
677
        return CodedOutputStream.computeEnumSizeNoTag(
 
678
            ((Internal.EnumLite) value).getNumber());
 
679
    }
 
680
 
 
681
    throw new RuntimeException(
 
682
      "There is no way to get here, but the compiler thinks otherwise.");
 
683
  }
 
684
 
 
685
  /**
 
686
   * Compute the number of bytes needed to encode a particular field.
 
687
   */
 
688
  public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
 
689
                                     final Object value) {
 
690
    WireFormat.FieldType type = descriptor.getLiteType();
 
691
    int number = descriptor.getNumber();
 
692
    if (descriptor.isRepeated()) {
 
693
      if (descriptor.isPacked()) {
 
694
        int dataSize = 0;
 
695
        for (final Object element : (List)value) {
 
696
          dataSize += computeElementSizeNoTag(type, element);
 
697
        }
 
698
        return dataSize +
 
699
            CodedOutputStream.computeTagSize(number) +
 
700
            CodedOutputStream.computeRawVarint32Size(dataSize);
 
701
      } else {
 
702
        int size = 0;
 
703
        for (final Object element : (List)value) {
 
704
          size += computeElementSize(type, number, element);
 
705
        }
 
706
        return size;
 
707
      }
 
708
    } else {
 
709
      return computeElementSize(type, number, value);
 
710
    }
 
711
  }
724
712
}