pbliteserializer.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Protocol Buffer 2 Serializer which serializes messages
  16. * into PB-Lite ("JsPbLite") format.
  17. *
  18. * PB-Lite format is an array where each index corresponds to the associated tag
  19. * number. For example, a message like so:
  20. *
  21. * message Foo {
  22. * optional int bar = 1;
  23. * optional int baz = 2;
  24. * optional int bop = 4;
  25. * }
  26. *
  27. * would be represented as such:
  28. *
  29. * [, (bar data), (baz data), (nothing), (bop data)]
  30. *
  31. * Note that since the array index is used to represent the tag number, sparsely
  32. * populated messages with tag numbers that are not continuous (and/or are very
  33. * large) will have many (empty) spots and thus, are inefficient.
  34. *
  35. *
  36. */
  37. goog.provide('goog.proto2.PbLiteSerializer');
  38. goog.require('goog.asserts');
  39. goog.require('goog.proto2.FieldDescriptor');
  40. goog.require('goog.proto2.LazyDeserializer');
  41. goog.require('goog.proto2.Serializer');
  42. /**
  43. * PB-Lite serializer.
  44. *
  45. * @constructor
  46. * @extends {goog.proto2.LazyDeserializer}
  47. */
  48. goog.proto2.PbLiteSerializer = function() {};
  49. goog.inherits(goog.proto2.PbLiteSerializer, goog.proto2.LazyDeserializer);
  50. /**
  51. * If true, fields will be serialized with 0-indexed tags (i.e., the proto
  52. * field with tag id 1 will have index 0 in the array).
  53. * @type {boolean}
  54. * @private
  55. */
  56. goog.proto2.PbLiteSerializer.prototype.zeroIndexing_ = false;
  57. /**
  58. * By default, the proto tag with id 1 will have index 1 in the serialized
  59. * array.
  60. *
  61. * If the serializer is set to use zero-indexing, the tag with id 1 will have
  62. * index 0.
  63. *
  64. * @param {boolean} zeroIndexing Whether this serializer should deal with
  65. * 0-indexed protos.
  66. */
  67. goog.proto2.PbLiteSerializer.prototype.setZeroIndexed = function(zeroIndexing) {
  68. this.zeroIndexing_ = zeroIndexing;
  69. };
  70. /**
  71. * Serializes a message to a PB-Lite object.
  72. *
  73. * @param {goog.proto2.Message} message The message to be serialized.
  74. * @return {!Array<?>} The serialized form of the message.
  75. * @override
  76. */
  77. goog.proto2.PbLiteSerializer.prototype.serialize = function(message) {
  78. var descriptor = message.getDescriptor();
  79. var fields = descriptor.getFields();
  80. var serialized = [];
  81. var zeroIndexing = this.zeroIndexing_;
  82. // Add the known fields.
  83. for (var i = 0; i < fields.length; i++) {
  84. var field = fields[i];
  85. if (!message.has(field)) {
  86. continue;
  87. }
  88. var tag = field.getTag();
  89. var index = zeroIndexing ? tag - 1 : tag;
  90. if (field.isRepeated()) {
  91. serialized[index] = [];
  92. for (var j = 0; j < message.countOf(field); j++) {
  93. serialized[index][j] =
  94. this.getSerializedValue(field, message.get(field, j));
  95. }
  96. } else {
  97. serialized[index] = this.getSerializedValue(field, message.get(field));
  98. }
  99. }
  100. // Add any unknown fields.
  101. message.forEachUnknown(function(tag, value) {
  102. var index = zeroIndexing ? tag - 1 : tag;
  103. serialized[index] = value;
  104. });
  105. return serialized;
  106. };
  107. /** @override */
  108. goog.proto2.PbLiteSerializer.prototype.deserializeField = function(
  109. message, field, value) {
  110. if (value == null) {
  111. // Since value double-equals null, it may be either null or undefined.
  112. // Ensure we return the same one, since they have different meanings.
  113. // TODO(user): If the field is repeated, this method should probably
  114. // return [] instead of null.
  115. return value;
  116. }
  117. if (field.isRepeated()) {
  118. var data = [];
  119. goog.asserts.assert(goog.isArray(value), 'Value must be array: %s', value);
  120. for (var i = 0; i < value.length; i++) {
  121. data[i] = this.getDeserializedValue(field, value[i]);
  122. }
  123. return data;
  124. } else {
  125. return this.getDeserializedValue(field, value);
  126. }
  127. };
  128. /** @override */
  129. goog.proto2.PbLiteSerializer.prototype.getSerializedValue = function(
  130. field, value) {
  131. if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.BOOL) {
  132. // Booleans are serialized in numeric form.
  133. return value ? 1 : 0;
  134. }
  135. return goog.proto2.Serializer.prototype.getSerializedValue.apply(
  136. this, arguments);
  137. };
  138. /** @override */
  139. goog.proto2.PbLiteSerializer.prototype.getDeserializedValue = function(
  140. field, value) {
  141. if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.BOOL) {
  142. goog.asserts.assert(
  143. goog.isNumber(value) || goog.isBoolean(value),
  144. 'Value is expected to be a number or boolean');
  145. return !!value;
  146. }
  147. return goog.proto2.Serializer.prototype.getDeserializedValue.apply(
  148. this, arguments);
  149. };
  150. /** @override */
  151. goog.proto2.PbLiteSerializer.prototype.deserialize = function(
  152. descriptor, data) {
  153. var toConvert = data;
  154. if (this.zeroIndexing_) {
  155. // Make the data align with tag-IDs (1-indexed) by shifting everything
  156. // up one.
  157. toConvert = [];
  158. for (var key in data) {
  159. toConvert[parseInt(key, 10) + 1] = data[key];
  160. }
  161. }
  162. return goog.proto2.PbLiteSerializer.base(
  163. this, 'deserialize', descriptor, toConvert);
  164. };