PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/game_server/src/com/google/protobuf/FieldSet.java

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