goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.crypt.base64');
+goog.require('jspb.BinaryReader');
goog.require('jspb.Map');
// Not needed in compilation units that have no protos with xids.
* dead code eliminate fields used in protocol buffers that are never used
* in an application.
*/
-goog.define('jspb.Message.GENERATE_TO_OBJECT', true);
+jspb.Message.GENERATE_TO_OBJECT =
+ goog.define('jspb.Message.GENERATE_TO_OBJECT', true);
/**
* calling fromObject. Enabling this might disable the JSCompiler's ability
* to dead code eliminate fields used in protocol buffers that are never
* used in an application.
- * NOTE: By default no protos actually have a fromObject method. You need to
- * add the jspb.generate_from_object options to the proto definition to
- * activate the feature.
* By default this is enabled for test code only.
*/
-goog.define('jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
+jspb.Message.GENERATE_FROM_OBJECT = goog.define(
+ 'jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
/**
* this off if you do not use toString in your project and want to trim it
* from the compiled JS.
*/
-goog.define('jspb.Message.GENERATE_TO_STRING', true);
+jspb.Message.GENERATE_TO_STRING =
+ goog.define('jspb.Message.GENERATE_TO_STRING', true);
/**
* local (e.g. not from another iframe) and thus safely classified with
* instanceof Array.
*/
-goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
+jspb.Message.ASSUME_LOCAL_ARRAYS =
+ goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
// TODO(jakubvrana): Turn this off by default.
* the proto before serialization. This is enabled by default to be
* backwards compatible. Projects are advised to turn this flag always off.
*/
-goog.define('jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS', true);
+jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS =
+ goog.define('jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS', true);
/**
/**
- * Repeated float or double fields which have been converted to include only
- * numbers and not strings holding "NaN", "Infinity" and "-Infinity".
+ * Repeated fields that have been converted to their proper type. This is used
+ * for numbers stored as strings (typically "NaN", "Infinity" and "-Infinity")
+ * and for booleans stored as numbers (0 or 1).
* @private {!Object<number,boolean>|undefined}
*/
-jspb.Message.prototype.convertedFloatingPointFields_;
-
+jspb.Message.prototype.convertedPrimitiveFields_;
/**
* Repeated fields numbers.
return fieldNumber + msg.arrayIndexOffset_;
};
+// This is only here to ensure we are not back sliding on ES6 requiements for
+// protos in g3.
+jspb.Message.hiddenES6Property_ = class {};
+
/**
* Returns the tag number based on the index in msg.array.
msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0;
msg.array = data;
jspb.Message.initPivotAndExtensionObject_(msg, suggestedPivot);
- msg.convertedFloatingPointFields_ = {};
+ msg.convertedPrimitiveFields_ = {};
if (!jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS) {
// TODO(jakubvrana): This is same for all instances, move to prototype.
goog.isArray(o);
};
+/**
+ * Returns true if the provided argument is an extension object.
+ * @param {*} o The object to classify as array or not.
+ * @return {boolean} True if the provided object is an extension object.
+ * @private
+ */
+jspb.Message.isExtensionObject_ = function(o) {
+ // Normal fields are never objects, so we can be sure that if we find an
+ // object here, then it's the extension object. However, we must ensure that
+ // the object is not an array, since arrays are valid field values (bytes
+ // fields can also be array).
+ // 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.
+ return (o !== null && typeof o == 'object' &&
+ !jspb.Message.isArray_(o) &&
+ !(jspb.Message.SUPPORTS_UINT8ARRAY_ && o instanceof Uint8Array));
+};
+
/**
* If the array contains an extension object in its last position, then the
* @private
*/
jspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
- if (msg.array.length) {
- var foundIndex = msg.array.length - 1;
- var obj = msg.array[foundIndex];
- // Normal fields are never objects, so we can be sure that if we find an
- // object here, then it's the extension object. However, we must ensure that
- // 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' && !jspb.Message.isArray_(obj) &&
- !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
- msg.pivot_ = jspb.Message.getFieldNumber_(msg, foundIndex);
+ // There are 3 variants that need to be dealt with which are the
+ // combination of whether there exists an extension object (EO) and
+ // whether there is a suggested pivot (SP).
+ //
+ // EO, ? : pivot is the index of the EO
+ // no-EO, no-SP: pivot is MAX_INT
+ // no-EO, SP : pivot is the max(lastindex + 1, SP)
+
+ var msgLength = msg.array.length;
+ var lastIndex = -1;
+ if (msgLength) {
+ lastIndex = msgLength - 1;
+ var obj = msg.array[lastIndex];
+ if (jspb.Message.isExtensionObject_(obj)) {
+ msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex);
msg.extensionObject_ = obj;
return;
}
}
if (suggestedPivot > -1) {
- msg.pivot_ = suggestedPivot;
+ // If a extension object is not present, set the pivot value as being
+ // after the last value in the array to avoid overwriting values, etc.
+ msg.pivot_ = Math.max(
+ suggestedPivot, jspb.Message.getFieldNumber_(msg, lastIndex + 1));
// Avoid changing the shape of the proto with an empty extension object by
// deferring the materialization of the extension object until the first
// time a field set into it (may be due to getting a repeated proto field
* Reads an extension field from the given reader and, if a valid extension,
* sets the extension value.
* @param {!jspb.Message} msg A jspb proto.
- * @param {{
- * skipField:function(this:jspb.BinaryReader),
- * getFieldNumber:function(this:jspb.BinaryReader):number
- * }} reader
+ * @param {!jspb.BinaryReader} reader
* @param {!Object} extensions The extensions object.
* @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo)} getExtensionFn
* @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo, ?)} setExtensionFn
* @protected
*/
jspb.Message.getRepeatedField = function(msg, fieldNumber) {
- if (fieldNumber < msg.pivot_) {
- var index = jspb.Message.getIndex_(msg, fieldNumber);
- var val = msg.array[index];
- if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
- return msg.array[index] = [];
- }
- return val;
- }
-
- var val = msg.extensionObject_[fieldNumber];
- if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
- return msg.extensionObject_[fieldNumber] = [];
- }
- return val;
+ return /** @type {!Array} */ (jspb.Message.getField(msg, fieldNumber));
};
/**
+ * Gets the value of an optional boolean field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @return {?boolean|undefined} The field's value.
+ * @protected
+ */
+jspb.Message.getBooleanField = function(msg, fieldNumber) {
+ var value = jspb.Message.getField(msg, fieldNumber);
+ // TODO(b/122673075): always return null when the value is null-ish.
+ return value == null ? (value) : !!value;
+};
+
+
+/**
* Gets the value of a repeated float or double field.
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
*/
jspb.Message.getRepeatedFloatingPointField = function(msg, fieldNumber) {
var values = jspb.Message.getRepeatedField(msg, fieldNumber);
- if (!msg.convertedFloatingPointFields_) {
- msg.convertedFloatingPointFields_ = {};
+ if (!msg.convertedPrimitiveFields_) {
+ msg.convertedPrimitiveFields_ = {};
}
- if (!msg.convertedFloatingPointFields_[fieldNumber]) {
+ if (!msg.convertedPrimitiveFields_[fieldNumber]) {
for (var i = 0; i < values.length; i++) {
// Converts "NaN", "Infinity" and "-Infinity" to their corresponding
// numbers.
values[i] = +values[i];
}
- msg.convertedFloatingPointFields_[fieldNumber] = true;
+ msg.convertedPrimitiveFields_[fieldNumber] = true;
}
return /** @type {!Array<number>} */ (values);
};
+/**
+ * Gets the value of a repeated boolean field.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @return {!Array<boolean>} The field's value.
+ * @protected
+ */
+jspb.Message.getRepeatedBooleanField = function(msg, fieldNumber) {
+ var values = jspb.Message.getRepeatedField(msg, fieldNumber);
+ if (!msg.convertedPrimitiveFields_) {
+ msg.convertedPrimitiveFields_ = {};
+ }
+ if (!msg.convertedPrimitiveFields_[fieldNumber]) {
+ for (var i = 0; i < values.length; i++) {
+ // Converts 0 and 1 to their corresponding booleans.
+ values[i] = !!values[i];
+ }
+ msg.convertedPrimitiveFields_[fieldNumber] = true;
+ }
+ return /** @type {!Array<boolean>} */ (values);
+};
+
/**
* Coerce a 'bytes' field to a base 64 string.
/**
+ * Gets the value of a boolean field, with proto3 (non-nullable primitives)
+ * semantics. Returns `defaultValue` if the field is not otherwise set.
+ * @template T
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {boolean} defaultValue The default value.
+ * @return {boolean} The field's value.
+ * @protected
+ */
+jspb.Message.getBooleanFieldWithDefault = function(
+ msg, fieldNumber, defaultValue) {
+ var value = jspb.Message.getBooleanField(msg, fieldNumber);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ return value;
+ }
+};
+
+
+/**
+ * Gets the value of a floating point field, with proto3 (non-nullable
+ * primitives) semantics. Returns `defaultValue` if the field is not otherwise
+ * set.
+ * @template T
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {number} defaultValue The default value.
+ * @return {number} The field's value.
+ * @protected
+ */
+jspb.Message.getFloatingPointFieldWithDefault = function(
+ msg, fieldNumber, defaultValue) {
+ var value = jspb.Message.getOptionalFloatingPointField(msg, fieldNumber);
+ if (value == null) {
+ return defaultValue;
+ } else {
+ return value;
+ }
+};
+
+
+/**
* Alias for getFieldWithDefault used by older generated code.
* @template T
* @param {!jspb.Message} msg A jspb proto.
/**
- * Sets the value of a non-extension integer, handled as string, field of a proto3
- * @param {!jspb.Message} msg A jspb proto.
- * @param {number} fieldNumber The field number.
- * @param {number} value New value
- * @protected
- */
-jspb.Message.setProto3StringIntField = function(msg, fieldNumber, value) {
- jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '0');
-};
-
-/**
* Sets the value of a non-extension floating point field of a proto3
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
};
+/**
+ * Sets the value of a non-extension int field of a proto3 that has jstype set
+ * to String.
+ * @param {!jspb.Message} msg A jspb proto.
+ * @param {number} fieldNumber The field number.
+ * @param {string} value New value
+ * @protected
+ */
+jspb.Message.setProto3StringIntField = function(msg, fieldNumber, value) {
+ jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, "0");
+};
/**
* Sets the value of a non-extension primitive field, with proto3 (non-nullable
* primitives) semantics of ignoring values that are equal to the type's
* default.
- * @template T
* @param {!jspb.Message} msg A jspb proto.
* @param {number} fieldNumber The field number.
* @param {!Uint8Array|string|number|boolean|undefined} value New value
*/
jspb.Message.setFieldIgnoringDefault_ = function(
msg, fieldNumber, value, defaultValue) {
- if (value != defaultValue) {
+ if (value !== defaultValue) {
jspb.Message.setField(msg, fieldNumber, value);
} else {
msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = null;
* @param {!jspb.Message} msg A jspb proto.
* @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
* @param {number} fieldNumber The field number.
- * @return {Array<!jspb.Message>} The repeated field as an array of protos.
+ * @return {!Array<!jspb.Message>} The repeated field as an array of protos.
* @protected
*/
jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {