| Index: third_party/protobuf/js/message.js
|
| diff --git a/third_party/protobuf/js/message.js b/third_party/protobuf/js/message.js
|
| index 813e6b8cd1d2f02a083c89892211fe4b15d95b0a..1eb88aef0300e213c5c8162d9f1c143e92138b76 100644
|
| --- a/third_party/protobuf/js/message.js
|
| +++ b/third_party/protobuf/js/message.js
|
| @@ -34,6 +34,7 @@
|
| * @author mwr@google.com (Mark Rawling)
|
| */
|
|
|
| +goog.provide('jspb.ExtensionFieldBinaryInfo');
|
| goog.provide('jspb.ExtensionFieldInfo');
|
| goog.provide('jspb.Message');
|
|
|
| @@ -41,6 +42,7 @@ goog.require('goog.array');
|
| goog.require('goog.asserts');
|
| goog.require('goog.crypt.base64');
|
| goog.require('goog.json');
|
| +goog.require('jspb.Map');
|
|
|
| // Not needed in compilation units that have no protos with xids.
|
| goog.forwardDeclare('xid.String');
|
| @@ -83,19 +85,12 @@ goog.forwardDeclare('xid.String');
|
| * @param {?function(new: jspb.Message, Array=)} ctor
|
| * @param {?function((boolean|undefined),!jspb.Message):!Object} toObjectFn
|
| * @param {number} isRepeated
|
| - * @param {?function(number,?)=} opt_binaryReaderFn
|
| - * @param {?function(number,?)|function(number,?,?,?,?,?)=} opt_binaryWriterFn
|
| - * @param {?function(?,?)=} opt_binaryMessageSerializeFn
|
| - * @param {?function(?,?)=} opt_binaryMessageDeserializeFn
|
| - * @param {?boolean=} opt_isPacked
|
| * @constructor
|
| * @struct
|
| * @template T
|
| */
|
| jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
|
| - isRepeated, opt_binaryReaderFn, opt_binaryWriterFn,
|
| - opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn,
|
| - opt_isPacked) {
|
| + isRepeated) {
|
| /** @const */
|
| this.fieldIndex = fieldNumber;
|
| /** @const */
|
| @@ -105,20 +100,37 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
|
| /** @const */
|
| this.toObjectFn = toObjectFn;
|
| /** @const */
|
| - this.binaryReaderFn = opt_binaryReaderFn;
|
| + this.isRepeated = isRepeated;
|
| +};
|
| +
|
| +/**
|
| + * Stores binary-related information for a single extension field.
|
| + * @param {!jspb.ExtensionFieldInfo<T>} fieldInfo
|
| + * @param {!function(number,?)} binaryReaderFn
|
| + * @param {!function(number,?)|function(number,?,?,?,?,?)} binaryWriterFn
|
| + * @param {function(?,?)=} opt_binaryMessageSerializeFn
|
| + * @param {function(?,?)=} opt_binaryMessageDeserializeFn
|
| + * @param {boolean=} opt_isPacked
|
| + * @constructor
|
| + * @struct
|
| + * @template T
|
| + */
|
| +jspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriterFn,
|
| + opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn, opt_isPacked) {
|
| + /** @const */
|
| + this.fieldInfo = fieldInfo;
|
| + /** @const */
|
| + this.binaryReaderFn = binaryReaderFn;
|
| /** @const */
|
| - this.binaryWriterFn = opt_binaryWriterFn;
|
| + this.binaryWriterFn = binaryWriterFn;
|
| /** @const */
|
| this.binaryMessageSerializeFn = opt_binaryMessageSerializeFn;
|
| /** @const */
|
| this.binaryMessageDeserializeFn = opt_binaryMessageDeserializeFn;
|
| /** @const */
|
| - this.isRepeated = isRepeated;
|
| - /** @const */
|
| this.isPacked = opt_isPacked;
|
| };
|
|
|
| -
|
| /**
|
| * @return {boolean} Does this field represent a sub Message?
|
| */
|
| @@ -371,7 +383,8 @@ jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) {
|
| // the object is not an array, since arrays are valid field values.
|
| // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
|
| // in Safari on iOS 8. See the description of CL/86511464 for details.
|
| - if (obj && typeof obj == 'object' && !goog.isArray(obj)) {
|
| + if (obj && typeof obj == 'object' && !goog.isArray(obj) &&
|
| + !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
|
| msg.pivot_ = foundIndex - msg.arrayIndexOffset_;
|
| msg.extensionObject_ = obj;
|
| return;
|
| @@ -489,11 +502,13 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions,
|
| jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
|
| getExtensionFn) {
|
| for (var fieldNumber in extensions) {
|
| - var fieldInfo = extensions[fieldNumber];
|
| + var binaryFieldInfo = extensions[fieldNumber];
|
| + var fieldInfo = binaryFieldInfo.fieldInfo;
|
| +
|
| // The old codegen doesn't add the extra fields to ExtensionFieldInfo, so we
|
| // need to gracefully error-out here rather than produce a null dereference
|
| // below.
|
| - if (!fieldInfo.binaryWriterFn) {
|
| + if (!binaryFieldInfo.binaryWriterFn) {
|
| throw new Error('Message extension present that was generated ' +
|
| 'without binary serialization support');
|
| }
|
| @@ -506,16 +521,17 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
|
| // message may require binary support, so we can *only* catch this error
|
| // here, at runtime (and this decoupled codegen is the whole point of
|
| // extensions!).
|
| - if (fieldInfo.binaryMessageSerializeFn) {
|
| - fieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex,
|
| - value, fieldInfo.binaryMessageSerializeFn);
|
| + if (binaryFieldInfo.binaryMessageSerializeFn) {
|
| + binaryFieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex,
|
| + value, binaryFieldInfo.binaryMessageSerializeFn);
|
| } else {
|
| throw new Error('Message extension present holding submessage ' +
|
| 'without binary support enabled, and message is ' +
|
| 'being serialized to binary format');
|
| }
|
| } else {
|
| - fieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex, value);
|
| + binaryFieldInfo.binaryWriterFn.call(
|
| + writer, fieldInfo.fieldIndex, value);
|
| }
|
| }
|
| }
|
| @@ -533,12 +549,13 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
|
| */
|
| jspb.Message.readBinaryExtension = function(msg, reader, extensions,
|
| getExtensionFn, setExtensionFn) {
|
| - var fieldInfo = extensions[reader.getFieldNumber()];
|
| - if (!fieldInfo) {
|
| + var binaryFieldInfo = extensions[reader.getFieldNumber()];
|
| + if (!binaryFieldInfo) {
|
| reader.skipField();
|
| return;
|
| }
|
| - if (!fieldInfo.binaryReaderFn) {
|
| + var fieldInfo = binaryFieldInfo.fieldInfo;
|
| + if (!binaryFieldInfo.binaryReaderFn) {
|
| throw new Error('Deserializing extension whose generated code does not ' +
|
| 'support binary format');
|
| }
|
| @@ -546,14 +563,14 @@ jspb.Message.readBinaryExtension = function(msg, reader, extensions,
|
| var value;
|
| if (fieldInfo.isMessageType()) {
|
| value = new fieldInfo.ctor();
|
| - fieldInfo.binaryReaderFn.call(
|
| - reader, value, fieldInfo.binaryMessageDeserializeFn);
|
| + binaryFieldInfo.binaryReaderFn.call(
|
| + reader, value, binaryFieldInfo.binaryMessageDeserializeFn);
|
| } else {
|
| // All other types.
|
| - value = fieldInfo.binaryReaderFn.call(reader);
|
| + value = binaryFieldInfo.binaryReaderFn.call(reader);
|
| }
|
|
|
| - if (fieldInfo.isRepeated && !fieldInfo.isPacked) {
|
| + if (fieldInfo.isRepeated && !binaryFieldInfo.isPacked) {
|
| var currentList = getExtensionFn.call(msg, fieldInfo);
|
| if (!currentList) {
|
| setExtensionFn.call(msg, fieldInfo, [value]);
|
| @@ -727,7 +744,7 @@ jspb.Message.assertConsistentTypes_ = function(array) {
|
| * @return {T} The field's value.
|
| * @protected
|
| */
|
| -jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) {
|
| +jspb.Message.getFieldWithDefault = function(msg, fieldNumber, defaultValue) {
|
| var value = jspb.Message.getField(msg, fieldNumber);
|
| if (value == null) {
|
| return defaultValue;
|
| @@ -738,6 +755,58 @@ jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) {
|
|
|
|
|
| /**
|
| + * Alias for getFieldWithDefault used by older generated code.
|
| + * @template T
|
| + * @param {!jspb.Message} msg A jspb proto.
|
| + * @param {number} fieldNumber The field number.
|
| + * @param {T} defaultValue The default value.
|
| + * @return {T} The field's value.
|
| + * @protected
|
| + */
|
| +jspb.Message.getFieldProto3 = jspb.Message.getFieldWithDefault;
|
| +
|
| +
|
| +/**
|
| + * Gets the value of a map field, lazily creating the map container if
|
| + * necessary.
|
| + *
|
| + * This should only be called from generated code, because it requires knowledge
|
| + * of serialization/parsing callbacks (which are required by the map at
|
| + * construction time, and the map may be constructed here).
|
| + *
|
| + * @template K, V
|
| + * @param {!jspb.Message} msg
|
| + * @param {number} fieldNumber
|
| + * @param {boolean|undefined} noLazyCreate
|
| + * @param {?=} opt_valueCtor
|
| + * @return {!jspb.Map<K, V>|undefined}
|
| + * @protected
|
| + */
|
| +jspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
|
| + opt_valueCtor) {
|
| + if (!msg.wrappers_) {
|
| + msg.wrappers_ = {};
|
| + }
|
| + // If we already have a map in the map wrappers, return that.
|
| + if (fieldNumber in msg.wrappers_) {
|
| + return msg.wrappers_[fieldNumber];
|
| + } else if (noLazyCreate) {
|
| + return undefined;
|
| + } else {
|
| + // Wrap the underlying elements array with a Map.
|
| + var arr = jspb.Message.getField(msg, fieldNumber);
|
| + if (!arr) {
|
| + arr = [];
|
| + jspb.Message.setField(msg, fieldNumber, arr);
|
| + }
|
| + return msg.wrappers_[fieldNumber] =
|
| + new jspb.Map(
|
| + /** @type {!Array<!Array<!Object>>} */ (arr), opt_valueCtor);
|
| + }
|
| +};
|
| +
|
| +
|
| +/**
|
| * Sets the value of a non-extension field.
|
| * @param {!jspb.Message} msg A jspb proto.
|
| * @param {number} fieldNumber The field number.
|
| @@ -754,6 +823,24 @@ jspb.Message.setField = function(msg, fieldNumber, value) {
|
|
|
|
|
| /**
|
| + * Adds a value to a repeated, primitive field.
|
| + * @param {!jspb.Message} msg A jspb proto.
|
| + * @param {number} fieldNumber The field number.
|
| + * @param {string|number|boolean|!Uint8Array} value New value
|
| + * @param {number=} opt_index Index where to put new value.
|
| + * @protected
|
| + */
|
| +jspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) {
|
| + var arr = jspb.Message.getField(msg, fieldNumber);
|
| + if (opt_index != undefined) {
|
| + arr.splice(opt_index, 0, value);
|
| + } else {
|
| + arr.push(value);
|
| + }
|
| +};
|
| +
|
| +
|
| +/**
|
| * Sets the value of a field in a oneof union and clears all other fields in
|
| * the union.
|
| * @param {!jspb.Message} msg A jspb proto.
|
| @@ -850,6 +937,24 @@ jspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) {
|
| * @protected
|
| */
|
| jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
|
| + jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber);
|
| + var val = msg.wrappers_[fieldNumber];
|
| + if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
|
| + val = msg.wrappers_[fieldNumber] = [];
|
| + }
|
| + return /** @type {!Array<!jspb.Message>} */ (val);
|
| +};
|
| +
|
| +
|
| +/**
|
| + * Wraps underlying array into proto message representation if it wasn't done
|
| + * before.
|
| + * @param {!jspb.Message} msg A jspb proto.
|
| + * @param {function(new:jspb.Message, ?Array)} ctor Constructor for the field.
|
| + * @param {number} fieldNumber The field number.
|
| + * @private
|
| + */
|
| +jspb.Message.wrapRepeatedField_ = function(msg, ctor, fieldNumber) {
|
| if (!msg.wrappers_) {
|
| msg.wrappers_ = {};
|
| }
|
| @@ -860,11 +965,6 @@ jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
|
| }
|
| msg.wrappers_[fieldNumber] = wrappers;
|
| }
|
| - var val = msg.wrappers_[fieldNumber];
|
| - if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
|
| - val = msg.wrappers_[fieldNumber] = [];
|
| - }
|
| - return /** @type {Array<!jspb.Message>} */ (val);
|
| };
|
|
|
|
|
| @@ -872,7 +972,8 @@ jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
|
| * Sets a proto field and syncs it to the backing array.
|
| * @param {!jspb.Message} msg A jspb proto.
|
| * @param {number} fieldNumber The field number.
|
| - * @param {jspb.Message|undefined} value A new value for this proto field.
|
| + * @param {?jspb.Message|?jspb.Map|undefined} value A new value for this proto
|
| + * field.
|
| * @protected
|
| */
|
| jspb.Message.setWrapperField = function(msg, fieldNumber, value) {
|
| @@ -924,6 +1025,48 @@ jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
|
|
|
|
|
| /**
|
| + * Add a message to a repeated proto field.
|
| + * @param {!jspb.Message} msg A jspb proto.
|
| + * @param {number} fieldNumber The field number.
|
| + * @param {T_CHILD|undefined} value Proto that will be added to the
|
| + * repeated field.
|
| + * @param {function(new:T_CHILD, ?Array=)} ctor The constructor of the
|
| + * message type.
|
| + * @param {number|undefined} index Index at which to insert the value.
|
| + * @return {T_CHILD_NOT_UNDEFINED} proto that was inserted to the repeated field
|
| + * @template MessageType
|
| + * Use go/closure-ttl to declare a non-undefined version of T_CHILD. Replace the
|
| + * undefined in blah|undefined with none. This is necessary because the compiler
|
| + * will infer T_CHILD to be |undefined.
|
| + * @template T_CHILD
|
| + * @template T_CHILD_NOT_UNDEFINED :=
|
| + * cond(isUnknown(T_CHILD), unknown(),
|
| + * mapunion(T_CHILD, (X) =>
|
| + * cond(eq(X, 'undefined'), none(), X)))
|
| + * =:
|
| + * @protected
|
| + */
|
| +jspb.Message.addToRepeatedWrapperField = function(
|
| + msg, fieldNumber, value, ctor, index) {
|
| + jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber);
|
| + var wrapperArray = msg.wrappers_[fieldNumber];
|
| + if (!wrapperArray) {
|
| + wrapperArray = msg.wrappers_[fieldNumber] = [];
|
| + }
|
| + var insertedValue = value ? value : new ctor();
|
| + var array = jspb.Message.getField(msg, fieldNumber);
|
| + if (index != undefined) {
|
| + wrapperArray.splice(index, 0, insertedValue);
|
| + array.splice(index, 0, insertedValue.toArray());
|
| + } else {
|
| + wrapperArray.push(insertedValue);
|
| + array.push(insertedValue.toArray());
|
| + }
|
| + return insertedValue;
|
| +};
|
| +
|
| +
|
| +/**
|
| * Converts a JsPb repeated message field into a map. The map will contain
|
| * protos unless an optional toObject function is given, in which case it will
|
| * contain objects suitable for Soy rendering.
|
| @@ -953,12 +1096,45 @@ jspb.Message.toMap = function(
|
|
|
|
|
| /**
|
| + * Syncs all map fields' contents back to their underlying arrays.
|
| + * @private
|
| + */
|
| +jspb.Message.prototype.syncMapFields_ = function() {
|
| + // This iterates over submessage, map, and repeated fields, which is intended.
|
| + // Submessages can contain maps which also need to be synced.
|
| + //
|
| + // There is a lot of opportunity for optimization here. For example we could
|
| + // statically determine that some messages have no submessages with maps and
|
| + // optimize this method away for those just by generating one extra static
|
| + // boolean per message type.
|
| + if (this.wrappers_) {
|
| + for (var fieldNumber in this.wrappers_) {
|
| + var val = this.wrappers_[fieldNumber];
|
| + if (goog.isArray(val)) {
|
| + for (var i = 0; i < val.length; i++) {
|
| + if (val[i]) {
|
| + val[i].toArray();
|
| + }
|
| + }
|
| + } else {
|
| + // Works for submessages and maps.
|
| + if (val) {
|
| + val.toArray();
|
| + }
|
| + }
|
| + }
|
| + }
|
| +};
|
| +
|
| +
|
| +/**
|
| * Returns the internal array of this proto.
|
| * <p>Note: If you use this array to construct a second proto, the content
|
| * would then be partially shared between the two protos.
|
| * @return {!Array} The proto represented as an array.
|
| */
|
| jspb.Message.prototype.toArray = function() {
|
| + this.syncMapFields_();
|
| return this.array;
|
| };
|
|
|
| @@ -972,6 +1148,7 @@ jspb.Message.prototype.toArray = function() {
|
| * @override
|
| */
|
| jspb.Message.prototype.toString = function() {
|
| + this.syncMapFields_();
|
| return this.array.toString();
|
| };
|
|
|
| @@ -1023,32 +1200,39 @@ jspb.Message.prototype.getExtension = function(fieldInfo) {
|
| * @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set.
|
| * @param {jspb.Message|string|Uint8Array|number|boolean|Array?} value The value
|
| * to set.
|
| + * @return {THIS} For chaining
|
| + * @this {THIS}
|
| + * @template THIS
|
| */
|
| jspb.Message.prototype.setExtension = function(fieldInfo, value) {
|
| - if (!this.wrappers_) {
|
| - this.wrappers_ = {};
|
| + // Cast self, since the inferred THIS is unknown inside the function body.
|
| + // https://github.com/google/closure-compiler/issues/1411#issuecomment-232442220
|
| + var self = /** @type {!jspb.Message} */ (this);
|
| + if (!self.wrappers_) {
|
| + self.wrappers_ = {};
|
| }
|
| - jspb.Message.maybeInitEmptyExtensionObject_(this);
|
| + jspb.Message.maybeInitEmptyExtensionObject_(self);
|
| var fieldNumber = fieldInfo.fieldIndex;
|
| if (fieldInfo.isRepeated) {
|
| value = value || [];
|
| if (fieldInfo.isMessageType()) {
|
| - this.wrappers_[fieldNumber] = value;
|
| - this.extensionObject_[fieldNumber] = goog.array.map(
|
| + self.wrappers_[fieldNumber] = value;
|
| + self.extensionObject_[fieldNumber] = goog.array.map(
|
| /** @type {Array<jspb.Message>} */ (value), function(msg) {
|
| return msg.toArray();
|
| });
|
| } else {
|
| - this.extensionObject_[fieldNumber] = value;
|
| + self.extensionObject_[fieldNumber] = value;
|
| }
|
| } else {
|
| if (fieldInfo.isMessageType()) {
|
| - this.wrappers_[fieldNumber] = value;
|
| - this.extensionObject_[fieldNumber] = value ? value.toArray() : value;
|
| + self.wrappers_[fieldNumber] = value;
|
| + self.extensionObject_[fieldNumber] = value ? value.toArray() : value;
|
| } else {
|
| - this.extensionObject_[fieldNumber] = value;
|
| + self.extensionObject_[fieldNumber] = value;
|
| }
|
| }
|
| + return self;
|
| };
|
|
|
|
|
| @@ -1217,7 +1401,30 @@ jspb.Message.compareFields = function(field1, field2) {
|
|
|
|
|
| /**
|
| - * Static clone function. NOTE: A type-safe method called "cloneMessage" exists
|
| + * Templated, type-safe cloneMessage definition.
|
| + * @return {THIS}
|
| + * @this {THIS}
|
| + * @template THIS
|
| + */
|
| +jspb.Message.prototype.cloneMessage = function() {
|
| + return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this));
|
| +};
|
| +
|
| +/**
|
| + * Alias clone to cloneMessage. goog.object.unsafeClone uses clone to
|
| + * efficiently copy objects. Without this alias, copying jspb messages comes
|
| + * with a large performance penalty.
|
| + * @return {THIS}
|
| + * @this {THIS}
|
| + * @template THIS
|
| + */
|
| +jspb.Message.prototype.clone = function() {
|
| + return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this));
|
| +};
|
| +
|
| +/**
|
| + * Static clone function. NOTE: A type-safe method called "cloneMessage"
|
| + * exists
|
| * on each generated JsPb class. Do not call this function directly.
|
| * @param {!jspb.Message} msg A message to clone.
|
| * @return {!jspb.Message} A deep clone of the given message.
|
| @@ -1293,6 +1500,9 @@ jspb.Message.clone_ = function(obj) {
|
| }
|
| return clonedArray;
|
| }
|
| + if (jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array) {
|
| + return new Uint8Array(obj);
|
| + }
|
| var clone = {};
|
| for (var key in obj) {
|
| if ((o = obj[key]) != null) {
|
| @@ -1335,3 +1545,4 @@ jspb.Message.registry_ = {};
|
| * @type {!Object.<number, jspb.ExtensionFieldInfo>}
|
| */
|
| jspb.Message.messageSetExtensions = {};
|
| +jspb.Message.messageSetExtensionsBinary = {};
|
|
|