Update wmts-hidpi, add nicer-api-docs

This commit is contained in:
Andreas Hocevar
2014-05-06 13:02:46 -05:00
parent b3ac1afd00
commit 1e25fc5585
2239 changed files with 3726515 additions and 37010 deletions

View File

@@ -0,0 +1,200 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Protocol Buffer (Message) Descriptor class.
*/
goog.provide('goog.proto2.Descriptor');
goog.provide('goog.proto2.Metadata');
goog.require('goog.array');
goog.require('goog.object');
goog.require('goog.proto2.Util');
/**
* @typedef {{name: (string|undefined),
* fullName: (string|undefined),
* containingType: (goog.proto2.Message|undefined)}}
*/
goog.proto2.Metadata;
/**
* A class which describes a Protocol Buffer 2 Message.
*
* @param {function(new:goog.proto2.Message)} messageType Constructor for
* the message class that this descriptor describes.
* @param {!goog.proto2.Metadata} metadata The metadata about the message that
* will be used to construct this descriptor.
* @param {Array.<!goog.proto2.FieldDescriptor>} fields The fields of the
* message described by this descriptor.
*
* @constructor
*/
goog.proto2.Descriptor = function(messageType, metadata, fields) {
/**
* @type {function(new:goog.proto2.Message)}
* @private
*/
this.messageType_ = messageType;
/**
* @type {?string}
* @private
*/
this.name_ = metadata.name || null;
/**
* @type {?string}
* @private
*/
this.fullName_ = metadata.fullName || null;
/**
* @type {goog.proto2.Message|undefined}
* @private
*/
this.containingType_ = metadata.containingType;
/**
* The fields of the message described by this descriptor.
* @type {!Object.<number, !goog.proto2.FieldDescriptor>}
* @private
*/
this.fields_ = {};
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
this.fields_[field.getTag()] = field;
}
};
/**
* Returns the name of the message, if any.
*
* @return {?string} The name.
*/
goog.proto2.Descriptor.prototype.getName = function() {
return this.name_;
};
/**
* Returns the full name of the message, if any.
*
* @return {?string} The name.
*/
goog.proto2.Descriptor.prototype.getFullName = function() {
return this.fullName_;
};
/**
* Returns the descriptor of the containing message type or null if none.
*
* @return {goog.proto2.Descriptor} The descriptor.
*/
goog.proto2.Descriptor.prototype.getContainingType = function() {
if (!this.containingType_) {
return null;
}
return this.containingType_.getDescriptor();
};
/**
* Returns the fields in the message described by this descriptor ordered by
* tag.
*
* @return {!Array.<!goog.proto2.FieldDescriptor>} The array of field
* descriptors.
*/
goog.proto2.Descriptor.prototype.getFields = function() {
/**
* @param {!goog.proto2.FieldDescriptor} fieldA First field.
* @param {!goog.proto2.FieldDescriptor} fieldB Second field.
* @return {number} Negative if fieldA's tag number is smaller, positive
* if greater, zero if the same.
*/
function tagComparator(fieldA, fieldB) {
return fieldA.getTag() - fieldB.getTag();
};
var fields = goog.object.getValues(this.fields_);
goog.array.sort(fields, tagComparator);
return fields;
};
/**
* Returns the fields in the message as a key/value map, where the key is
* the tag number of the field. DO NOT MODIFY THE RETURNED OBJECT. We return
* the actual, internal, fields map for performance reasons, and changing the
* map can result in undefined behavior of this library.
*
* @return {!Object.<number, !goog.proto2.FieldDescriptor>} The field map.
*/
goog.proto2.Descriptor.prototype.getFieldsMap = function() {
return this.fields_;
};
/**
* Returns the field matching the given name, if any. Note that
* this method searches over the *original* name of the field,
* not the camelCase version.
*
* @param {string} name The field name for which to search.
*
* @return {goog.proto2.FieldDescriptor} The field found, if any.
*/
goog.proto2.Descriptor.prototype.findFieldByName = function(name) {
var valueFound = goog.object.findValue(this.fields_,
function(field, key, obj) {
return field.getName() == name;
});
return /** @type {goog.proto2.FieldDescriptor} */ (valueFound) || null;
};
/**
* Returns the field matching the given tag number, if any.
*
* @param {number|string} tag The field tag number for which to search.
*
* @return {goog.proto2.FieldDescriptor} The field found, if any.
*/
goog.proto2.Descriptor.prototype.findFieldByTag = function(tag) {
goog.proto2.Util.assert(goog.string.isNumeric(tag));
return this.fields_[parseInt(tag, 10)] || null;
};
/**
* Creates an instance of the message type that this descriptor
* describes.
*
* @return {!goog.proto2.Message} The instance of the message.
*/
goog.proto2.Descriptor.prototype.createMessageInstance = function() {
return new this.messageType_;
};

View File

@@ -0,0 +1,291 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Protocol Buffer Field Descriptor class.
*/
goog.provide('goog.proto2.FieldDescriptor');
goog.require('goog.proto2.Util');
goog.require('goog.string');
/**
* A class which describes a field in a Protocol Buffer 2 Message.
*
* @param {Function} messageType Constructor for the message
* class to which the field described by this class belongs.
* @param {number|string} tag The field's tag index.
* @param {Object} metadata The metadata about this field that will be used
* to construct this descriptor.
*
* @constructor
*/
goog.proto2.FieldDescriptor = function(messageType, tag, metadata) {
/**
* The message type that contains the field that this
* descriptor describes.
* @type {Function}
* @private
*/
this.parent_ = messageType;
// Ensure that the tag is numeric.
goog.proto2.Util.assert(goog.string.isNumeric(tag));
/**
* The field's tag number.
* @type {number}
* @private
*/
this.tag_ = /** @type {number} */ (tag);
/**
* The field's name.
* @type {string}
* @private
*/
this.name_ = metadata.name;
/** @type {goog.proto2.FieldDescriptor.FieldType} */
metadata.fieldType;
/** @type {*} */
metadata.repeated;
/** @type {*} */
metadata.required;
/**
* If true, this field is a repeating field.
* @type {boolean}
* @private
*/
this.isRepeated_ = !!metadata.repeated;
/**
* If true, this field is required.
* @type {boolean}
* @private
*/
this.isRequired_ = !!metadata.required;
/**
* The field type of this field.
* @type {goog.proto2.FieldDescriptor.FieldType}
* @private
*/
this.fieldType_ = metadata.fieldType;
/**
* If this field is a primitive: The native (ECMAScript) type of this field.
* If an enumeration: The enumeration object.
* If a message or group field: The Message function.
* @type {Function}
* @private
*/
this.nativeType_ = metadata.type;
/**
* Is it permissible on deserialization to convert between numbers and
* well-formed strings? Is true for 64-bit integral field types, false for
* all other field types.
* @type {boolean}
* @private
*/
this.deserializationConversionPermitted_ = false;
switch (this.fieldType_) {
case goog.proto2.FieldDescriptor.FieldType.INT64:
case goog.proto2.FieldDescriptor.FieldType.UINT64:
case goog.proto2.FieldDescriptor.FieldType.FIXED64:
case goog.proto2.FieldDescriptor.FieldType.SFIXED64:
case goog.proto2.FieldDescriptor.FieldType.SINT64:
this.deserializationConversionPermitted_ = true;
break;
}
/**
* The default value of this field, if different from the default, default
* value.
* @type {*}
* @private
*/
this.defaultValue_ = metadata.defaultValue;
};
/**
* An enumeration defining the possible field types.
* Should be a mirror of that defined in descriptor.h.
*
* @enum {number}
*/
goog.proto2.FieldDescriptor.FieldType = {
DOUBLE: 1,
FLOAT: 2,
INT64: 3,
UINT64: 4,
INT32: 5,
FIXED64: 6,
FIXED32: 7,
BOOL: 8,
STRING: 9,
GROUP: 10,
MESSAGE: 11,
BYTES: 12,
UINT32: 13,
ENUM: 14,
SFIXED32: 15,
SFIXED64: 16,
SINT32: 17,
SINT64: 18
};
/**
* Returns the tag of the field that this descriptor represents.
*
* @return {number} The tag number.
*/
goog.proto2.FieldDescriptor.prototype.getTag = function() {
return this.tag_;
};
/**
* Returns the descriptor describing the message that defined this field.
* @return {goog.proto2.Descriptor} The descriptor.
*/
goog.proto2.FieldDescriptor.prototype.getContainingType = function() {
return this.parent_.getDescriptor();
};
/**
* Returns the name of the field that this descriptor represents.
* @return {string} The name.
*/
goog.proto2.FieldDescriptor.prototype.getName = function() {
return this.name_;
};
/**
* Returns the default value of this field.
* @return {*} The default value.
*/
goog.proto2.FieldDescriptor.prototype.getDefaultValue = function() {
if (this.defaultValue_ === undefined) {
// Set the default value based on a new instance of the native type.
// This will be (0, false, "") for (number, boolean, string) and will
// be a new instance of a group/message if the field is a message type.
var nativeType = this.nativeType_;
if (nativeType === Boolean) {
this.defaultValue_ = false;
} else if (nativeType === Number) {
this.defaultValue_ = 0;
} else if (nativeType === String) {
this.defaultValue_ = '';
} else {
this.defaultValue_ = new nativeType;
}
}
return this.defaultValue_;
};
/**
* Returns the field type of the field described by this descriptor.
* @return {goog.proto2.FieldDescriptor.FieldType} The field type.
*/
goog.proto2.FieldDescriptor.prototype.getFieldType = function() {
return this.fieldType_;
};
/**
* Returns the native (i.e. ECMAScript) type of the field described by this
* descriptor.
*
* @return {Object} The native type.
*/
goog.proto2.FieldDescriptor.prototype.getNativeType = function() {
return this.nativeType_;
};
/**
* Returns true if simple conversions between numbers and strings are permitted
* during deserialization for this field.
*
* @return {boolean} Whether conversion is permitted.
*/
goog.proto2.FieldDescriptor.prototype.deserializationConversionPermitted =
function() {
return this.deserializationConversionPermitted_;
};
/**
* Returns the descriptor of the message type of this field. Only valid
* for fields of type GROUP and MESSAGE.
*
* @return {goog.proto2.Descriptor} The message descriptor.
*/
goog.proto2.FieldDescriptor.prototype.getFieldMessageType = function() {
goog.proto2.Util.assert(this.isCompositeType(), 'Expected message or group');
return this.nativeType_.getDescriptor();
};
/**
* @return {boolean} True if the field stores composite data or repeated
* composite data (message or group).
*/
goog.proto2.FieldDescriptor.prototype.isCompositeType = function() {
return this.fieldType_ == goog.proto2.FieldDescriptor.FieldType.MESSAGE ||
this.fieldType_ == goog.proto2.FieldDescriptor.FieldType.GROUP;
};
/**
* Returns whether the field described by this descriptor is repeating.
* @return {boolean} Whether the field is repeated.
*/
goog.proto2.FieldDescriptor.prototype.isRepeated = function() {
return this.isRepeated_;
};
/**
* Returns whether the field described by this descriptor is required.
* @return {boolean} Whether the field is required.
*/
goog.proto2.FieldDescriptor.prototype.isRequired = function() {
return this.isRequired_;
};
/**
* Returns whether the field described by this descriptor is optional.
* @return {boolean} Whether the field is optional.
*/
goog.proto2.FieldDescriptor.prototype.isOptional = function() {
return !this.isRepeated_ && !this.isRequired_;
};

View File

@@ -0,0 +1,70 @@
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Base class for all PB2 lazy deserializer. A lazy deserializer
* is a serializer whose deserialization occurs on the fly as data is
* requested. In order to use a lazy deserializer, the serialized form
* of the data must be an object or array that can be indexed by the tag
* number.
*
*/
goog.provide('goog.proto2.LazyDeserializer');
goog.require('goog.proto2.Message');
goog.require('goog.proto2.Serializer');
goog.require('goog.proto2.Util');
/**
* Base class for all lazy deserializers.
*
* @constructor
* @extends {goog.proto2.Serializer}
*/
goog.proto2.LazyDeserializer = function() {};
goog.inherits(goog.proto2.LazyDeserializer, goog.proto2.Serializer);
/** @override */
goog.proto2.LazyDeserializer.prototype.deserialize =
function(descriptor, data) {
var message = descriptor.createMessageInstance();
message.initializeForLazyDeserializer(this, data);
goog.proto2.Util.assert(message instanceof goog.proto2.Message);
return message;
};
/** @override */
goog.proto2.LazyDeserializer.prototype.deserializeTo = function(message, data) {
throw new Error('Unimplemented');
};
/**
* Deserializes a message field from the expected format and places the
* data in the given message
*
* @param {goog.proto2.Message} message The message in which to
* place the information.
* @param {goog.proto2.FieldDescriptor} field The field for which to set the
* message value.
* @param {*} data The serialized data for the field.
*
* @return {*} The deserialized data or null for no value found.
*/
goog.proto2.LazyDeserializer.prototype.deserializeField = goog.abstractMethod;

View File

@@ -0,0 +1,840 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Protocol Buffer Message base class.
*/
goog.provide('goog.proto2.Message');
goog.require('goog.proto2.Descriptor');
goog.require('goog.proto2.FieldDescriptor');
goog.require('goog.proto2.Util');
goog.require('goog.string');
/**
* Abstract base class for all Protocol Buffer 2 messages. It will be
* subclassed in the code generated by the Protocol Compiler. Any other
* subclasses are prohibited.
* @constructor
*/
goog.proto2.Message = function() {
/**
* Stores the field values in this message. Keyed by the tag of the fields.
* @type {*}
* @private
*/
this.values_ = {};
/**
* Stores the field information (i.e. metadata) about this message.
* @type {Object.<number, !goog.proto2.FieldDescriptor>}
* @private
*/
this.fields_ = this.getDescriptor().getFieldsMap();
/**
* The lazy deserializer for this message instance, if any.
* @type {goog.proto2.LazyDeserializer}
* @private
*/
this.lazyDeserializer_ = null;
/**
* A map of those fields deserialized, from tag number to their deserialized
* value.
* @type {Object}
* @private
*/
this.deserializedFields_ = null;
};
/**
* An enumeration defining the possible field types.
* Should be a mirror of that defined in descriptor.h.
*
* TODO(user): Remove this alias. The code generator generates code that
* references this enum, so it needs to exist until the code generator is
* changed. The enum was moved to from Message to FieldDescriptor to avoid a
* dependency cycle.
*
* Use goog.proto2.FieldDescriptor.FieldType instead.
*
* @enum {number}
*/
goog.proto2.Message.FieldType = {
DOUBLE: 1,
FLOAT: 2,
INT64: 3,
UINT64: 4,
INT32: 5,
FIXED64: 6,
FIXED32: 7,
BOOL: 8,
STRING: 9,
GROUP: 10,
MESSAGE: 11,
BYTES: 12,
UINT32: 13,
ENUM: 14,
SFIXED32: 15,
SFIXED64: 16,
SINT32: 17,
SINT64: 18
};
/**
* All instances of goog.proto2.Message should have a static descriptorObj_
* property. This is a JSON representation of a Descriptor. The real Descriptor
* will be deserialized lazily in the getDescriptor() method.
*
* This declaration is just here for documentation purposes.
* goog.proto2.Message does not have its own descriptor.
*
* @type {undefined}
* @private
*/
goog.proto2.Message.descriptorObj_;
/**
* All instances of goog.proto2.Message should have a static descriptor_
* property. The Descriptor will be deserialized lazily in the getDescriptor()
* method.
*
* This declaration is just here for documentation purposes.
* goog.proto2.Message does not have its own descriptor.
*
* @type {undefined}
* @private
*/
goog.proto2.Message.descriptor_;
/**
* Initializes the message with a lazy deserializer and its associated data.
* This method should be called by internal methods ONLY.
*
* @param {goog.proto2.LazyDeserializer} deserializer The lazy deserializer to
* use to decode the data on the fly.
*
* @param {*} data The data to decode/deserialize.
*/
goog.proto2.Message.prototype.initializeForLazyDeserializer = function(
deserializer, data) {
this.lazyDeserializer_ = deserializer;
this.values_ = data;
this.deserializedFields_ = {};
};
/**
* Sets the value of an unknown field, by tag.
*
* @param {number} tag The tag of an unknown field (must be >= 1).
* @param {*} value The value for that unknown field.
*/
goog.proto2.Message.prototype.setUnknown = function(tag, value) {
goog.proto2.Util.assert(!this.fields_[tag],
'Field is not unknown in this message');
goog.proto2.Util.assert(tag >= 1, 'Tag is not valid');
goog.proto2.Util.assert(value !== null, 'Value cannot be null');
this.values_[tag] = value;
if (this.deserializedFields_) {
delete this.deserializedFields_[tag];
}
};
/**
* Iterates over all the unknown fields in the message.
*
* @param {function(number, *)} callback A callback method
* which gets invoked for each unknown field.
* @param {Object=} opt_scope The scope under which to execute the callback.
* If not given, the current message will be used.
*/
goog.proto2.Message.prototype.forEachUnknown = function(callback, opt_scope) {
var scope = opt_scope || this;
for (var key in this.values_) {
var keyNum = Number(key);
if (!this.fields_[keyNum]) {
callback.call(scope, keyNum, this.values_[key]);
}
}
};
/**
* Returns the descriptor which describes the current message.
*
* This only works if we assume people never subclass protobufs.
*
* @return {!goog.proto2.Descriptor} The descriptor.
*/
goog.proto2.Message.prototype.getDescriptor = function() {
// NOTE(nicksantos): These sorts of indirect references to descriptor
// through this.constructor are fragile. See the comments
// in set$Metadata for more info.
var Ctor = this.constructor;
return Ctor.descriptor_ ||
(Ctor.descriptor_ = goog.proto2.Message.create$Descriptor(
Ctor, Ctor.descriptorObj_));
};
/**
* Returns whether there is a value stored at the field specified by the
* given field descriptor.
*
* @param {goog.proto2.FieldDescriptor} field The field for which to check
* if there is a value.
*
* @return {boolean} True if a value was found.
*/
goog.proto2.Message.prototype.has = function(field) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
return this.has$Value(field.getTag());
};
/**
* Returns the array of values found for the given repeated field.
*
* @param {goog.proto2.FieldDescriptor} field The field for which to
* return the values.
*
* @return {!Array} The values found.
*/
goog.proto2.Message.prototype.arrayOf = function(field) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
return this.array$Values(field.getTag());
};
/**
* Returns the number of values stored in the given field.
*
* @param {goog.proto2.FieldDescriptor} field The field for which to count
* the number of values.
*
* @return {number} The count of the values in the given field.
*/
goog.proto2.Message.prototype.countOf = function(field) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
return this.count$Values(field.getTag());
};
/**
* Returns the value stored at the field specified by the
* given field descriptor.
*
* @param {goog.proto2.FieldDescriptor} field The field for which to get the
* value.
* @param {number=} opt_index If the field is repeated, the index to use when
* looking up the value.
*
* @return {*} The value found or null if none.
*/
goog.proto2.Message.prototype.get = function(field, opt_index) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
return this.get$Value(field.getTag(), opt_index);
};
/**
* Returns the value stored at the field specified by the
* given field descriptor or the default value if none exists.
*
* @param {goog.proto2.FieldDescriptor} field The field for which to get the
* value.
* @param {number=} opt_index If the field is repeated, the index to use when
* looking up the value.
*
* @return {*} The value found or the default if none.
*/
goog.proto2.Message.prototype.getOrDefault = function(field, opt_index) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
return this.get$ValueOrDefault(field.getTag(), opt_index);
};
/**
* Stores the given value to the field specified by the
* given field descriptor. Note that the field must not be repeated.
*
* @param {goog.proto2.FieldDescriptor} field The field for which to set
* the value.
* @param {*} value The new value for the field.
*/
goog.proto2.Message.prototype.set = function(field, value) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
this.set$Value(field.getTag(), value);
};
/**
* Adds the given value to the field specified by the
* given field descriptor. Note that the field must be repeated.
*
* @param {goog.proto2.FieldDescriptor} field The field in which to add the
* the value.
* @param {*} value The new value to add to the field.
*/
goog.proto2.Message.prototype.add = function(field, value) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
this.add$Value(field.getTag(), value);
};
/**
* Clears the field specified.
*
* @param {goog.proto2.FieldDescriptor} field The field to clear.
*/
goog.proto2.Message.prototype.clear = function(field) {
goog.proto2.Util.assert(
field.getContainingType() == this.getDescriptor(),
'The current message does not contain the given field');
this.clear$Field(field.getTag());
};
/**
* Compares this message with another one ignoring the unknown fields.
* @param {*} other The other message.
* @return {boolean} Whether they are equal. Returns false if the {@code other}
* argument is a different type of message or not a message.
*/
goog.proto2.Message.prototype.equals = function(other) {
if (!other || this.constructor != other.constructor) {
return false;
}
var fields = this.getDescriptor().getFields();
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
if (this.has(field) != other.has(field)) {
return false;
}
if (this.has(field)) {
var isComposite = field.isCompositeType();
var fieldsEqual = function(value1, value2) {
return isComposite ? value1.equals(value2) : value1 == value2;
};
var thisValue = this.getValueForField_(field);
var otherValue = other.getValueForField_(field);
if (field.isRepeated()) {
// In this case thisValue and otherValue are arrays.
if (thisValue.length != otherValue.length) {
return false;
}
for (var j = 0; j < thisValue.length; j++) {
if (!fieldsEqual(thisValue[j], otherValue[j])) {
return false;
}
}
} else if (!fieldsEqual(thisValue, otherValue)) {
return false;
}
}
}
return true;
};
/**
* Recursively copies the known fields from the given message to this message.
* Removes the fields which are not present in the source message.
* @param {!goog.proto2.Message} message The source message.
*/
goog.proto2.Message.prototype.copyFrom = function(message) {
goog.proto2.Util.assert(this.constructor == message.constructor,
'The source message must have the same type.');
if (this != message) {
this.values_ = {};
if (this.deserializedFields_) {
this.deserializedFields_ = {};
}
this.mergeFrom(message);
}
};
/**
* Merges the given message into this message.
*
* Singular fields will be overwritten, except for embedded messages which will
* be merged. Repeated fields will be concatenated.
* @param {!goog.proto2.Message} message The source message.
*/
goog.proto2.Message.prototype.mergeFrom = function(message) {
goog.proto2.Util.assert(this.constructor == message.constructor,
'The source message must have the same type.');
var fields = this.getDescriptor().getFields();
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
if (message.has(field)) {
if (this.deserializedFields_) {
delete this.deserializedFields_[field.getTag()];
}
var isComposite = field.isCompositeType();
if (field.isRepeated()) {
var values = message.arrayOf(field);
for (var j = 0; j < values.length; j++) {
this.add(field, isComposite ? values[j].clone() : values[j]);
}
} else {
var value = message.getValueForField_(field);
if (isComposite) {
var child = this.getValueForField_(field);
if (child) {
child.mergeFrom(value);
} else {
this.set(field, value.clone());
}
} else {
this.set(field, value);
}
}
}
}
};
/**
* @return {!goog.proto2.Message} Recursive clone of the message only including
* the known fields.
*/
goog.proto2.Message.prototype.clone = function() {
var clone = new this.constructor;
clone.copyFrom(this);
return clone;
};
/**
* Fills in the protocol buffer with default values. Any fields that are
* already set will not be overridden.
* @param {boolean} simpleFieldsToo If true, all fields will be initialized;
* if false, only the nested messages and groups.
*/
goog.proto2.Message.prototype.initDefaults = function(simpleFieldsToo) {
var fields = this.getDescriptor().getFields();
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var tag = field.getTag();
var isComposite = field.isCompositeType();
// Initialize missing fields.
if (!this.has(field) && !field.isRepeated()) {
if (isComposite) {
this.values_[tag] = new /** @type {Function} */ (field.getNativeType());
} else if (simpleFieldsToo) {
this.values_[tag] = field.getDefaultValue();
}
}
// Fill in the existing composite fields recursively.
if (isComposite) {
if (field.isRepeated()) {
var values = this.array$Values(tag);
for (var j = 0; j < values.length; j++) {
values[j].initDefaults(simpleFieldsToo);
}
} else {
this.get$Value(tag).initDefaults(simpleFieldsToo);
}
}
}
};
/**
* Returns the field in this message by the given tag number. If no
* such field exists, throws an exception.
*
* @param {number} tag The field's tag index.
* @return {!goog.proto2.FieldDescriptor} The descriptor for the field.
* @private
*/
goog.proto2.Message.prototype.getFieldByTag_ = function(tag) {
goog.proto2.Util.assert(this.fields_[tag],
'No field found for the given tag');
return this.fields_[tag];
};
/**
* Returns the whether or not the field indicated by the given tag
* has a value.
*
* GENERATED CODE USE ONLY. Basis of the has{Field} methods.
*
* @param {number} tag The tag.
*
* @return {boolean} Whether the message has a value for the field.
*/
goog.proto2.Message.prototype.has$Value = function(tag) {
goog.proto2.Util.assert(this.fields_[tag],
'No field found for the given tag');
return tag in this.values_ && goog.isDef(this.values_[tag]) &&
this.values_[tag] !== null;
};
/**
* Returns the value for the given field. If a lazy deserializer is
* instantiated, lazily deserializes the field if required before returning the
* value.
*
* @param {goog.proto2.FieldDescriptor} field The field.
* @return {*} The field value, if any.
* @private
*/
goog.proto2.Message.prototype.getValueForField_ = function(field) {
// Retrieve the current value, which may still be serialized.
var tag = field.getTag();
if (!tag in this.values_) {
return null;
}
var value = this.values_[tag];
if (value == null) {
return null;
}
// If we have a lazy deserializer, then ensure that the field is
// properly deserialized.
if (this.lazyDeserializer_) {
// If the tag is not deserialized, then we must do so now. Deserialize
// the field's value via the deserializer.
if (!(tag in this.deserializedFields_)) {
var deserializedValue = this.lazyDeserializer_.deserializeField(
this, field, value);
this.deserializedFields_[tag] = deserializedValue;
return deserializedValue;
}
return this.deserializedFields_[tag];
}
// Otherwise, just return the value.
return value;
};
/**
* Gets the value at the field indicated by the given tag.
*
* GENERATED CODE USE ONLY. Basis of the get{Field} methods.
*
* @param {number} tag The field's tag index.
* @param {number=} opt_index If the field is a repeated field, the index
* at which to get the value.
*
* @return {*} The value found or null for none.
* @protected
*/
goog.proto2.Message.prototype.get$Value = function(tag, opt_index) {
var field = this.getFieldByTag_(tag);
var value = this.getValueForField_(field);
if (field.isRepeated()) {
goog.proto2.Util.assert(goog.isArray(value));
var index = opt_index || 0;
goog.proto2.Util.assert(index >= 0 && index < value.length,
'Given index is out of bounds');
return value[index];
}
goog.proto2.Util.assert(!goog.isArray(value));
return value;
};
/**
* Gets the value at the field indicated by the given tag or the default value
* if none.
*
* GENERATED CODE USE ONLY. Basis of the get{Field} methods.
*
* @param {number} tag The field's tag index.
* @param {number=} opt_index If the field is a repeated field, the index
* at which to get the value.
*
* @return {*} The value found or the default value if none set.
* @protected
*/
goog.proto2.Message.prototype.get$ValueOrDefault = function(tag, opt_index) {
if (!this.has$Value(tag)) {
// Return the default value.
var field = this.getFieldByTag_(tag);
return field.getDefaultValue();
}
return this.get$Value(tag, opt_index);
};
/**
* Gets the values at the field indicated by the given tag.
*
* GENERATED CODE USE ONLY. Basis of the {field}Array methods.
*
* @param {number} tag The field's tag index.
*
* @return {!Array} The values found. If none, returns an empty array.
* @protected
*/
goog.proto2.Message.prototype.array$Values = function(tag) {
goog.proto2.Util.assert(this.getFieldByTag_(tag).isRepeated(),
'Cannot call fieldArray on a non-repeated field');
var field = this.getFieldByTag_(tag);
var value = this.getValueForField_(field);
goog.proto2.Util.assert(value == null || goog.isArray(value));
return /** @type {Array} */ (value) || [];
};
/**
* Returns the number of values stored in the field by the given tag.
*
* GENERATED CODE USE ONLY. Basis of the {field}Count methods.
*
* @param {number} tag The tag.
*
* @return {number} The number of values.
* @protected
*/
goog.proto2.Message.prototype.count$Values = function(tag) {
var field = this.getFieldByTag_(tag);
if (field.isRepeated()) {
if (this.has$Value(tag)) {
goog.proto2.Util.assert(goog.isArray(this.values_[tag]));
}
return this.has$Value(tag) ? this.values_[tag].length : 0;
} else {
return this.has$Value(tag) ? 1 : 0;
}
};
/**
* Sets the value of the *non-repeating* field indicated by the given tag.
*
* GENERATED CODE USE ONLY. Basis of the set{Field} methods.
*
* @param {number} tag The field's tag index.
* @param {*} value The field's value.
* @protected
*/
goog.proto2.Message.prototype.set$Value = function(tag, value) {
if (goog.proto2.Util.conductChecks()) {
var field = this.getFieldByTag_(tag);
goog.proto2.Util.assert(!field.isRepeated(),
'Cannot call set on a repeated field');
this.checkFieldType_(field, value);
}
this.values_[tag] = value;
if (this.deserializedFields_) {
this.deserializedFields_[tag] = value;
}
};
/**
* Adds the value to the *repeating* field indicated by the given tag.
*
* GENERATED CODE USE ONLY. Basis of the add{Field} methods.
*
* @param {number} tag The field's tag index.
* @param {*} value The value to add.
* @protected
*/
goog.proto2.Message.prototype.add$Value = function(tag, value) {
if (goog.proto2.Util.conductChecks()) {
var field = this.getFieldByTag_(tag);
goog.proto2.Util.assert(field.isRepeated(),
'Cannot call add on a non-repeated field');
this.checkFieldType_(field, value);
}
if (!this.values_[tag]) {
this.values_[tag] = [];
}
this.values_[tag].push(value);
if (this.deserializedFields_) {
delete this.deserializedFields_[tag];
}
};
/**
* Ensures that the value being assigned to the given field
* is valid.
*
* @param {!goog.proto2.FieldDescriptor} field The field being assigned.
* @param {*} value The value being assigned.
* @private
*/
goog.proto2.Message.prototype.checkFieldType_ = function(field, value) {
goog.proto2.Util.assert(value !== null);
var nativeType = field.getNativeType();
if (nativeType === String) {
goog.proto2.Util.assert(typeof value === 'string',
'Expected value of type string');
} else if (nativeType === Boolean) {
goog.proto2.Util.assert(typeof value === 'boolean',
'Expected value of type boolean');
} else if (nativeType === Number) {
goog.proto2.Util.assert(typeof value === 'number',
'Expected value of type number');
} else if (field.getFieldType() ==
goog.proto2.FieldDescriptor.FieldType.ENUM) {
goog.proto2.Util.assert(typeof value === 'number',
'Expected an enum value, which is a number');
} else {
goog.proto2.Util.assert(value instanceof nativeType,
'Expected a matching message type');
}
};
/**
* Clears the field specified by tag.
*
* GENERATED CODE USE ONLY. Basis of the clear{Field} methods.
*
* @param {number} tag The tag of the field to clear.
* @protected
*/
goog.proto2.Message.prototype.clear$Field = function(tag) {
goog.proto2.Util.assert(this.getFieldByTag_(tag), 'Unknown field');
delete this.values_[tag];
if (this.deserializedFields_) {
delete this.deserializedFields_[tag];
}
};
/**
* Creates the metadata descriptor representing the definition of this message.
*
* GENERATED CODE USE ONLY. Called when constructing message classes.
*
* @param {function(new:goog.proto2.Message)} messageType Constructor for the
* message type to which this metadata applies.
* @param {Object} metadataObj The object containing the metadata.
* @return {!goog.proto2.Descriptor} The new descriptor.
*/
goog.proto2.Message.create$Descriptor = function(messageType, metadataObj) {
var fields = [];
var descriptorInfo;
for (var key in metadataObj) {
if (!metadataObj.hasOwnProperty(key)) {
continue;
}
goog.proto2.Util.assert(goog.string.isNumeric(key), 'Keys must be numeric');
if (key == 0) {
descriptorInfo = metadataObj[0];
continue;
}
// Create the field descriptor.
fields.push(
new goog.proto2.FieldDescriptor(messageType, key, metadataObj[key]));
}
goog.proto2.Util.assert(descriptorInfo);
return new goog.proto2.Descriptor(messageType, descriptorInfo, fields);
};
/**
* Sets the metadata that represents the definition of this message.
*
* GENERATED CODE USE ONLY. Called when constructing message classes.
*
* @param {!Function} messageType Constructor for the
* message type to which this metadata applies.
* @param {Object} metadataObj The object containing the metadata.
*/
goog.proto2.Message.set$Metadata = function(messageType, metadataObj) {
// NOTE(nicksantos): JSCompiler's type-based optimizations really do not
// like indirectly defined methods (both prototype methods and
// static methods). This is very fragile in compiled code. I think it only
// really works by accident, and is highly likely to break in the future.
messageType.descriptorObj_ = metadataObj;
messageType.getDescriptor = function() {
// The descriptor is created lazily when we instantiate a new instance.
return messageType.descriptor_ ||
(new messageType()).getDescriptor();
};
};

View File

@@ -0,0 +1,159 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Protocol Buffer 2 Serializer which serializes messages
* into anonymous, simplified JSON objects.
*
*/
goog.provide('goog.proto2.ObjectSerializer');
goog.require('goog.proto2.Serializer');
goog.require('goog.proto2.Util');
goog.require('goog.string');
/**
* ObjectSerializer, a serializer which turns Messages into simplified
* ECMAScript objects.
*
* @param {goog.proto2.ObjectSerializer.KeyOption=} opt_keyOption If specified,
* which key option to use when serializing/deserializing.
* @constructor
* @extends {goog.proto2.Serializer}
*/
goog.proto2.ObjectSerializer = function(opt_keyOption) {
this.keyOption_ = opt_keyOption;
};
goog.inherits(goog.proto2.ObjectSerializer, goog.proto2.Serializer);
/**
* An enumeration of the options for how to emit the keys in
* the generated simplified object.
*
* @enum {number}
*/
goog.proto2.ObjectSerializer.KeyOption = {
/**
* Use the tag of the field as the key (default)
*/
TAG: 0,
/**
* Use the name of the field as the key. Unknown fields
* will still use their tags as keys.
*/
NAME: 1
};
/**
* Serializes a message to an object.
*
* @param {goog.proto2.Message} message The message to be serialized.
* @return {Object} The serialized form of the message.
* @override
*/
goog.proto2.ObjectSerializer.prototype.serialize = function(message) {
var descriptor = message.getDescriptor();
var fields = descriptor.getFields();
var objectValue = {};
// Add the defined fields, recursively.
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var key =
this.keyOption_ == goog.proto2.ObjectSerializer.KeyOption.NAME ?
field.getName() : field.getTag();
if (message.has(field)) {
if (field.isRepeated()) {
var array = [];
objectValue[key] = array;
for (var j = 0; j < message.countOf(field); j++) {
array.push(this.getSerializedValue(field, message.get(field, j)));
}
} else {
objectValue[key] = this.getSerializedValue(field, message.get(field));
}
}
}
// Add the unknown fields, if any.
message.forEachUnknown(function(tag, value) {
objectValue[tag] = value;
});
return objectValue;
};
/**
* Deserializes a message from an object and places the
* data in the message.
*
* @param {goog.proto2.Message} message The message in which to
* place the information.
* @param {*} data The data of the message.
* @override
*/
goog.proto2.ObjectSerializer.prototype.deserializeTo = function(message, data) {
var descriptor = message.getDescriptor();
for (var key in data) {
var field;
var value = data[key];
var isNumeric = goog.string.isNumeric(key);
if (isNumeric) {
field = descriptor.findFieldByTag(key);
} else {
// We must be in Key == NAME mode to lookup by name.
goog.proto2.Util.assert(
this.keyOption_ == goog.proto2.ObjectSerializer.KeyOption.NAME);
field = descriptor.findFieldByName(key);
}
if (field) {
if (field.isRepeated()) {
goog.proto2.Util.assert(goog.isArray(value));
for (var j = 0; j < value.length; j++) {
message.add(field, this.getDeserializedValue(field, value[j]));
}
} else {
goog.proto2.Util.assert(!goog.isArray(value));
message.set(field, this.getDeserializedValue(field, value));
}
} else {
if (isNumeric) {
// We have an unknown field.
message.setUnknown(Number(key), value);
} else {
// Named fields must be present.
goog.proto2.Util.assert(field);
}
}
}
};

View File

@@ -0,0 +1,166 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// All other code copyright its respective owners(s).
/**
* @fileoverview Generated Protocol Buffer code for file
* closure/goog/proto2/package_test.proto.
*/
goog.provide('someprotopackage.TestPackageTypes');
goog.require('goog.proto2.Message');
goog.require('proto2.TestAllTypes');
goog.setTestOnly('package_test.pb');
/**
* Message TestPackageTypes.
* @constructor
* @extends {goog.proto2.Message}
*/
someprotopackage.TestPackageTypes = function() {
goog.proto2.Message.apply(this);
};
goog.inherits(someprotopackage.TestPackageTypes, goog.proto2.Message);
/**
* Overrides {@link goog.proto2.Message#clone} to specify its exact return type.
* @return {!someprotopackage.TestPackageTypes} The cloned message.
* @override
*/
someprotopackage.TestPackageTypes.prototype.clone;
/**
* Gets the value of the optional_int32 field.
* @return {?number} The value.
*/
someprotopackage.TestPackageTypes.prototype.getOptionalInt32 = function() {
return /** @type {?number} */ (this.get$Value(1));
};
/**
* Gets the value of the optional_int32 field or the default value if not set.
* @return {number} The value.
*/
someprotopackage.TestPackageTypes.prototype.getOptionalInt32OrDefault = function() {
return /** @type {number} */ (this.get$ValueOrDefault(1));
};
/**
* Sets the value of the optional_int32 field.
* @param {number} value The value.
*/
someprotopackage.TestPackageTypes.prototype.setOptionalInt32 = function(value) {
this.set$Value(1, value);
};
/**
* @return {boolean} Whether the optional_int32 field has a value.
*/
someprotopackage.TestPackageTypes.prototype.hasOptionalInt32 = function() {
return this.has$Value(1);
};
/**
* @return {number} The number of values in the optional_int32 field.
*/
someprotopackage.TestPackageTypes.prototype.optionalInt32Count = function() {
return this.count$Values(1);
};
/**
* Clears the values in the optional_int32 field.
*/
someprotopackage.TestPackageTypes.prototype.clearOptionalInt32 = function() {
this.clear$Field(1);
};
/**
* Gets the value of the other_all field.
* @return {proto2.TestAllTypes} The value.
*/
someprotopackage.TestPackageTypes.prototype.getOtherAll = function() {
return /** @type {proto2.TestAllTypes} */ (this.get$Value(2));
};
/**
* Gets the value of the other_all field or the default value if not set.
* @return {!proto2.TestAllTypes} The value.
*/
someprotopackage.TestPackageTypes.prototype.getOtherAllOrDefault = function() {
return /** @type {!proto2.TestAllTypes} */ (this.get$ValueOrDefault(2));
};
/**
* Sets the value of the other_all field.
* @param {!proto2.TestAllTypes} value The value.
*/
someprotopackage.TestPackageTypes.prototype.setOtherAll = function(value) {
this.set$Value(2, value);
};
/**
* @return {boolean} Whether the other_all field has a value.
*/
someprotopackage.TestPackageTypes.prototype.hasOtherAll = function() {
return this.has$Value(2);
};
/**
* @return {number} The number of values in the other_all field.
*/
someprotopackage.TestPackageTypes.prototype.otherAllCount = function() {
return this.count$Values(2);
};
/**
* Clears the values in the other_all field.
*/
someprotopackage.TestPackageTypes.prototype.clearOtherAll = function() {
this.clear$Field(2);
};
goog.proto2.Message.set$Metadata(someprotopackage.TestPackageTypes, {
0: {
name: 'TestPackageTypes',
fullName: 'someprotopackage.TestPackageTypes'
},
1: {
name: 'optional_int32',
fieldType: goog.proto2.Message.FieldType.INT32,
type: Number
},
2: {
name: 'other_all',
fieldType: goog.proto2.Message.FieldType.MESSAGE,
type: proto2.TestAllTypes
}
});

View File

@@ -0,0 +1,193 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Protocol Buffer 2 Serializer which serializes messages
* into PB-Lite ("JsPbLite") format.
*
* PB-Lite format is an array where each index corresponds to the associated tag
* number. For example, a message like so:
*
* message Foo {
* optional int bar = 1;
* optional int baz = 2;
* optional int bop = 4;
* }
*
* would be represented as such:
*
* [, (bar data), (baz data), (nothing), (bop data)]
*
* Note that since the array index is used to represent the tag number, sparsely
* populated messages with tag numbers that are not continuous (and/or are very
* large) will have many (empty) spots and thus, are inefficient.
*
*
*/
goog.provide('goog.proto2.PbLiteSerializer');
goog.require('goog.proto2.LazyDeserializer');
goog.require('goog.proto2.Util');
/**
* PB-Lite serializer.
*
* @constructor
* @extends {goog.proto2.LazyDeserializer}
*/
goog.proto2.PbLiteSerializer = function() {};
goog.inherits(goog.proto2.PbLiteSerializer, goog.proto2.LazyDeserializer);
/**
* If true, fields will be serialized with 0-indexed tags (i.e., the proto
* field with tag id 1 will have index 0 in the array).
* @type {boolean}
* @private
*/
goog.proto2.PbLiteSerializer.prototype.zeroIndexing_ = false;
/**
* By default, the proto tag with id 1 will have index 1 in the serialized
* array.
*
* If the serializer is set to use zero-indexing, the tag with id 1 will have
* index 0.
*
* @param {boolean} zeroIndexing Whether this serializer should deal with
* 0-indexed protos.
*/
goog.proto2.PbLiteSerializer.prototype.setZeroIndexed = function(zeroIndexing) {
this.zeroIndexing_ = zeroIndexing;
};
/**
* Serializes a message to a PB-Lite object.
*
* @param {goog.proto2.Message} message The message to be serialized.
* @return {!Array} The serialized form of the message.
* @override
*/
goog.proto2.PbLiteSerializer.prototype.serialize = function(message) {
var descriptor = message.getDescriptor();
var fields = descriptor.getFields();
var serialized = [];
var zeroIndexing = this.zeroIndexing_;
// Add the known fields.
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
if (!message.has(field)) {
continue;
}
var tag = field.getTag();
var index = zeroIndexing ? tag - 1 : tag;
if (field.isRepeated()) {
serialized[index] = [];
for (var j = 0; j < message.countOf(field); j++) {
serialized[index][j] =
this.getSerializedValue(field, message.get(field, j));
}
} else {
serialized[index] = this.getSerializedValue(field, message.get(field));
}
}
// Add any unknown fields.
message.forEachUnknown(function(tag, value) {
var index = zeroIndexing ? tag - 1 : tag;
serialized[index] = value;
});
return serialized;
};
/** @override */
goog.proto2.PbLiteSerializer.prototype.deserializeField =
function(message, field, value) {
if (value == null) {
// Since value double-equals null, it may be either null or undefined.
// Ensure we return the same one, since they have different meanings.
return value;
}
if (field.isRepeated()) {
var data = [];
goog.proto2.Util.assert(goog.isArray(value));
for (var i = 0; i < value.length; i++) {
data[i] = this.getDeserializedValue(field, value[i]);
}
return data;
} else {
return this.getDeserializedValue(field, value);
}
};
/** @override */
goog.proto2.PbLiteSerializer.prototype.getSerializedValue =
function(field, value) {
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.BOOL) {
// Booleans are serialized in numeric form.
return value ? 1 : 0;
}
return goog.proto2.Serializer.prototype.getSerializedValue.apply(this,
arguments);
};
/** @override */
goog.proto2.PbLiteSerializer.prototype.getDeserializedValue =
function(field, value) {
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.BOOL) {
// Booleans are serialized in numeric form.
return value === 1;
}
return goog.proto2.Serializer.prototype.getDeserializedValue.apply(this,
arguments);
};
/** @override */
goog.proto2.PbLiteSerializer.prototype.deserialize =
function(descriptor, data) {
var toConvert = data;
if (this.zeroIndexing_) {
// Make the data align with tag-IDs (1-indexed) by shifting everything
// up one.
toConvert = [];
for (var key in data) {
toConvert[parseInt(key, 10) + 1] = data[key];
}
}
return goog.base(this, 'deserialize', descriptor, toConvert);
};

View File

@@ -0,0 +1,174 @@
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Base class for all Protocol Buffer 2 serializers.
*/
goog.provide('goog.proto2.Serializer');
goog.require('goog.proto2.Descriptor');
goog.require('goog.proto2.FieldDescriptor');
goog.require('goog.proto2.Message');
goog.require('goog.proto2.Util');
/**
* Abstract base class for PB2 serializers. A serializer is a class which
* implements the serialization and deserialization of a Protocol Buffer Message
* to/from a specific format.
*
* @constructor
*/
goog.proto2.Serializer = function() {};
/**
* @define {boolean} Whether to decode and convert symbolic enum values to
* actual enum values or leave them as strings.
*/
goog.define('goog.proto2.Serializer.DECODE_SYMBOLIC_ENUMS', false);
/**
* Serializes a message to the expected format.
*
* @param {goog.proto2.Message} message The message to be serialized.
*
* @return {*} The serialized form of the message.
*/
goog.proto2.Serializer.prototype.serialize = goog.abstractMethod;
/**
* Returns the serialized form of the given value for the given field
* if the field is a Message or Group and returns the value unchanged
* otherwise.
*
* @param {goog.proto2.FieldDescriptor} field The field from which this
* value came.
*
* @param {*} value The value of the field.
*
* @return {*} The value.
* @protected
*/
goog.proto2.Serializer.prototype.getSerializedValue = function(field, value) {
if (field.isCompositeType()) {
return this.serialize(/** @type {goog.proto2.Message} */ (value));
} else {
return value;
}
};
/**
* Deserializes a message from the expected format.
*
* @param {goog.proto2.Descriptor} descriptor The descriptor of the message
* to be created.
* @param {*} data The data of the message.
*
* @return {goog.proto2.Message} The message created.
*/
goog.proto2.Serializer.prototype.deserialize = function(descriptor, data) {
var message = descriptor.createMessageInstance();
this.deserializeTo(message, data);
goog.proto2.Util.assert(message instanceof goog.proto2.Message);
return message;
};
/**
* Deserializes a message from the expected format and places the
* data in the message.
*
* @param {goog.proto2.Message} message The message in which to
* place the information.
* @param {*} data The data of the message.
*/
goog.proto2.Serializer.prototype.deserializeTo = goog.abstractMethod;
/**
* Returns the deserialized form of the given value for the given field if the
* field is a Message or Group and returns the value, converted or unchanged,
* for primitive field types otherwise.
*
* @param {goog.proto2.FieldDescriptor} field The field from which this
* value came.
*
* @param {*} value The value of the field.
*
* @return {*} The value.
* @protected
*/
goog.proto2.Serializer.prototype.getDeserializedValue = function(field, value) {
// Composite types are deserialized recursively.
if (field.isCompositeType()) {
if (value instanceof goog.proto2.Message) {
return value;
}
return this.deserialize(field.getFieldMessageType(), value);
}
// Decode enum values.
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.ENUM) {
// If it's a string, get enum value by name.
// NB: In order this feature to work, property renaming should be turned off
// for the respective enums.
if (goog.proto2.Serializer.DECODE_SYMBOLIC_ENUMS && goog.isString(value)) {
// enumType is a regular Javascript enum as defined in field's metadata.
var enumType = field.getNativeType();
if (enumType.hasOwnProperty(value)) {
return enumType[value];
}
}
// Return unknown values as is for backward compatibility.
return value;
}
// Return the raw value if the field does not allow the JSON input to be
// converted.
if (!field.deserializationConversionPermitted()) {
return value;
}
// Convert to native type of field. Return the converted value or fall
// through to return the raw value. The JSON encoding of int64 value 123
// might be either the number 123 or the string "123". The field native type
// could be either Number or String (depending on field options in the .proto
// file). All four combinations should work correctly.
var nativeType = field.getNativeType();
if (nativeType === String) {
// JSON numbers can be converted to strings.
if (goog.isNumber(value)) {
return String(value);
}
} else if (nativeType === Number) {
// JSON strings are sometimes used for large integer numeric values.
if (goog.isString(value)) {
// Validate the string. If the string is not an integral number, we would
// rather have an assertion or error in the caller than a mysterious NaN
// value.
if (/^-?[0-9]+$/.test(value)) {
return Number(value);
}
}
}
return value;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,995 @@
// Copyright 2011 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Protocol Buffer 2 Serializer which serializes messages
* into a user-friendly text format. Note that this code can run a bit
* slowly (especially for parsing) and should therefore not be used for
* time or space-critical applications.
*
* @see http://goo.gl/QDmDr
*/
goog.provide('goog.proto2.TextFormatSerializer');
goog.provide('goog.proto2.TextFormatSerializer.Parser');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.json');
goog.require('goog.proto2.Serializer');
goog.require('goog.proto2.Util');
goog.require('goog.string');
/**
* TextFormatSerializer, a serializer which turns Messages into the human
* readable text format.
* @param {boolean=} opt_ignoreMissingFields If true, then fields that cannot be
* found on the proto when parsing the text format will be ignored.
* @constructor
* @extends {goog.proto2.Serializer}
*/
goog.proto2.TextFormatSerializer = function(opt_ignoreMissingFields) {
/**
* Whether to ignore fields not defined on the proto when parsing the text
* format.
* @type {boolean}
* @private
*/
this.ignoreMissingFields_ = !!opt_ignoreMissingFields;
};
goog.inherits(goog.proto2.TextFormatSerializer, goog.proto2.Serializer);
/**
* Deserializes a message from text format and places the data in the message.
* @param {goog.proto2.Message} message The message in which to
* place the information.
* @param {*} data The text format data.
* @return {?string} The parse error or null on success.
* @override
*/
goog.proto2.TextFormatSerializer.prototype.deserializeTo =
function(message, data) {
var descriptor = message.getDescriptor();
var textData = data.toString();
var parser = new goog.proto2.TextFormatSerializer.Parser();
if (!parser.parse(message, textData, this.ignoreMissingFields_)) {
return parser.getError();
}
return null;
};
/**
* Serializes a message to a string.
* @param {goog.proto2.Message} message The message to be serialized.
* @return {string} The serialized form of the message.
* @override
*/
goog.proto2.TextFormatSerializer.prototype.serialize = function(message) {
var printer = new goog.proto2.TextFormatSerializer.Printer_();
this.serializeMessage_(message, printer);
return printer.toString();
};
/**
* Serializes the message and prints the text form into the given printer.
* @param {goog.proto2.Message} message The message to serialize.
* @param {goog.proto2.TextFormatSerializer.Printer_} printer The printer to
* which the text format will be printed.
* @private
*/
goog.proto2.TextFormatSerializer.prototype.serializeMessage_ =
function(message, printer) {
var descriptor = message.getDescriptor();
var fields = descriptor.getFields();
// Add the defined fields, recursively.
goog.array.forEach(fields, function(field) {
this.printField_(message, field, printer);
}, this);
// Add the unknown fields, if any.
message.forEachUnknown(function(tag, value) {
if (!value) { return; }
printer.append(tag);
if (goog.typeOf(value) == 'object') {
printer.append(' {');
printer.appendLine();
printer.indent();
} else {
printer.append(': ');
}
switch (goog.typeOf(value)) {
case 'string':
value = goog.string.quote(/** @type {string} */ (value));
printer.append(value);
break;
case 'object':
this.serializeMessage_(value, printer);
break;
default:
printer.append(value.toString());
break;
}
if (goog.typeOf(value) == 'object') {
printer.dedent();
printer.append('}');
} else {
printer.appendLine();
}
}, this);
};
/**
* Prints the serialized value for the given field to the printer.
* @param {*} value The field's value.
* @param {goog.proto2.FieldDescriptor} field The field whose value is being
* printed.
* @param {goog.proto2.TextFormatSerializer.Printer_} printer The printer to
* which the value will be printed.
* @private
*/
goog.proto2.TextFormatSerializer.prototype.printFieldValue_ =
function(value, field, printer) {
switch (field.getFieldType()) {
case goog.proto2.FieldDescriptor.FieldType.DOUBLE:
case goog.proto2.FieldDescriptor.FieldType.FLOAT:
case goog.proto2.FieldDescriptor.FieldType.INT64:
case goog.proto2.FieldDescriptor.FieldType.UINT64:
case goog.proto2.FieldDescriptor.FieldType.INT32:
case goog.proto2.FieldDescriptor.FieldType.UINT32:
case goog.proto2.FieldDescriptor.FieldType.FIXED64:
case goog.proto2.FieldDescriptor.FieldType.FIXED32:
case goog.proto2.FieldDescriptor.FieldType.BOOL:
case goog.proto2.FieldDescriptor.FieldType.SFIXED32:
case goog.proto2.FieldDescriptor.FieldType.SFIXED64:
case goog.proto2.FieldDescriptor.FieldType.SINT32:
case goog.proto2.FieldDescriptor.FieldType.SINT64:
printer.append(value);
break;
case goog.proto2.FieldDescriptor.FieldType.BYTES:
case goog.proto2.FieldDescriptor.FieldType.STRING:
value = goog.string.quote(value.toString());
printer.append(value);
break;
case goog.proto2.FieldDescriptor.FieldType.ENUM:
// Search the enum type for a matching key.
var found = false;
goog.object.forEach(field.getNativeType(), function(eValue, key) {
if (eValue == value) {
printer.append(key);
found = true;
}
});
if (!found) {
// Otherwise, just print the numeric value.
printer.append(value.toString());
}
break;
case goog.proto2.FieldDescriptor.FieldType.GROUP:
case goog.proto2.FieldDescriptor.FieldType.MESSAGE:
this.serializeMessage_(
/** @type {goog.proto2.Message} */ (value), printer);
break;
}
};
/**
* Prints the serialized field to the printer.
* @param {goog.proto2.Message} message The parent message.
* @param {goog.proto2.FieldDescriptor} field The field to print.
* @param {goog.proto2.TextFormatSerializer.Printer_} printer The printer to
* which the field will be printed.
* @private
*/
goog.proto2.TextFormatSerializer.prototype.printField_ =
function(message, field, printer) {
// Skip fields not present.
if (!message.has(field)) {
return;
}
var count = message.countOf(field);
for (var i = 0; i < count; ++i) {
// Field name.
printer.append(field.getName());
// Field delimiter.
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.MESSAGE ||
field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.GROUP) {
printer.append(' {');
printer.appendLine();
printer.indent();
} else {
printer.append(': ');
}
// Write the field value.
this.printFieldValue_(message.get(field, i), field, printer);
// Close the field.
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.MESSAGE ||
field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.GROUP) {
printer.dedent();
printer.append('}');
printer.appendLine();
} else {
printer.appendLine();
}
}
};
////////////////////////////////////////////////////////////////////////////////
/**
* Helper class used by the text format serializer for pretty-printing text.
* @constructor
* @private
*/
goog.proto2.TextFormatSerializer.Printer_ = function() {
/**
* The current indentation count.
* @type {number}
* @private
*/
this.indentation_ = 0;
/**
* The buffer of string pieces.
* @type {Array.<string>}
* @private
*/
this.buffer_ = [];
/**
* Whether indentation is required before the next append of characters.
* @type {boolean}
* @private
*/
this.requiresIndentation_ = true;
};
/**
* @return {string} The contents of the printer.
* @override
*/
goog.proto2.TextFormatSerializer.Printer_.prototype.toString = function() {
return this.buffer_.join('');
};
/**
* Increases the indentation in the printer.
*/
goog.proto2.TextFormatSerializer.Printer_.prototype.indent = function() {
this.indentation_ += 2;
};
/**
* Decreases the indentation in the printer.
*/
goog.proto2.TextFormatSerializer.Printer_.prototype.dedent = function() {
this.indentation_ -= 2;
goog.asserts.assert(this.indentation_ >= 0);
};
/**
* Appends the given value to the printer.
* @param {*} value The value to append.
*/
goog.proto2.TextFormatSerializer.Printer_.prototype.append = function(value) {
if (this.requiresIndentation_) {
for (var i = 0; i < this.indentation_; ++i) {
this.buffer_.push(' ');
}
this.requiresIndentation_ = false;
}
this.buffer_.push(value.toString());
};
/**
* Appends a newline to the printer.
*/
goog.proto2.TextFormatSerializer.Printer_.prototype.appendLine = function() {
this.buffer_.push('\n');
this.requiresIndentation_ = true;
};
////////////////////////////////////////////////////////////////////////////////
/**
* Helper class for tokenizing the text format.
* @param {string} data The string data to tokenize.
* @param {boolean=} opt_ignoreWhitespace If true, whitespace tokens will not
* be reported by the tokenizer.
* @constructor
* @private
*/
goog.proto2.TextFormatSerializer.Tokenizer_ =
function(data, opt_ignoreWhitespace) {
/**
* Whether to skip whitespace tokens on output.
* @type {boolean}
* @private
*/
this.ignoreWhitespace_ = !!opt_ignoreWhitespace;
/**
* The data being tokenized.
* @type {string}
* @private
*/
this.data_ = data;
/**
* The current index in the data.
* @type {number}
* @private
*/
this.index_ = 0;
/**
* The data string starting at the current index.
* @type {string}
* @private
*/
this.currentData_ = data;
/**
* The current token type.
* @type {goog.proto2.TextFormatSerializer.Tokenizer_.Token}
* @private
*/
this.current_ = {
type: goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes.END,
value: null
};
};
/**
* @typedef {{type: goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes,
* value: ?string}}
*/
goog.proto2.TextFormatSerializer.Tokenizer_.Token;
/**
* @return {goog.proto2.TextFormatSerializer.Tokenizer_.Token} The current
* token.
*/
goog.proto2.TextFormatSerializer.Tokenizer_.prototype.getCurrent = function() {
return this.current_;
};
/**
* An enumeration of all the token types.
* @enum {*}
*/
goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes = {
END: /---end---/,
// Leading "-" to identify "-infinity"."
IDENTIFIER: /^-?[a-zA-Z][a-zA-Z0-9_]*/,
NUMBER: /^(0x[0-9a-f]+)|(([-])?[0-9][0-9]*(\.?[0-9]+)?([f])?)/,
COMMENT: /^#.*/,
OPEN_BRACE: /^{/,
CLOSE_BRACE: /^}/,
OPEN_TAG: /^</,
CLOSE_TAG: /^>/,
OPEN_LIST: /^\[/,
CLOSE_LIST: /^\]/,
STRING: new RegExp('^"([^"\\\\]|\\\\.)*"'),
COLON: /^:/,
COMMA: /^,/,
SEMI: /^;/,
WHITESPACE: /^\s/
};
/**
* Advances to the next token.
* @return {boolean} True if a valid token was found, false if the end was
* reached or no valid token was found.
*/
goog.proto2.TextFormatSerializer.Tokenizer_.prototype.next = function() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
// Skip any whitespace if requested.
while (this.nextInternal_()) {
if (this.getCurrent().type != types.WHITESPACE || !this.ignoreWhitespace_) {
return true;
}
}
// If we reach this point, set the current token to END.
this.current_ = {
type: goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes.END,
value: null
};
return false;
};
/**
* Internal method for determining the next token.
* @return {boolean} True if a next token was found, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Tokenizer_.prototype.nextInternal_ =
function() {
if (this.index_ >= this.data_.length) {
return false;
}
var data = this.currentData_;
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
var next = null;
// Loop through each token type and try to match the beginning of the string
// with the token's regular expression.
goog.object.forEach(types, function(type, id) {
if (next || type == types.END) {
return;
}
// Note: This regular expression check is at, minimum, O(n).
var info = type.exec(data);
if (info && info.index == 0) {
next = {
type: type,
value: info[0]
};
}
});
// Advance the index by the length of the token.
if (next) {
this.current_ =
/** @type {goog.proto2.TextFormatSerializer.Tokenizer_.Token} */ (next);
this.index_ += next.value.length;
this.currentData_ = this.currentData_.substring(next.value.length);
}
return !!next;
};
////////////////////////////////////////////////////////////////////////////////
/**
* Helper class for parsing the text format.
* @constructor
*/
goog.proto2.TextFormatSerializer.Parser = function() {
/**
* The error during parsing, if any.
* @type {?string}
* @private
*/
this.error_ = null;
/**
* The current tokenizer.
* @type {goog.proto2.TextFormatSerializer.Tokenizer_}
* @private
*/
this.tokenizer_ = null;
/**
* Whether to ignore missing fields in the proto when parsing.
* @type {boolean}
* @private
*/
this.ignoreMissingFields_ = false;
};
/**
* Parses the given data, filling the message as it goes.
* @param {goog.proto2.Message} message The message to fill.
* @param {string} data The text format data.
* @param {boolean=} opt_ignoreMissingFields If true, fields missing in the
* proto will be ignored.
* @return {boolean} True on success, false on failure. On failure, the
* getError method can be called to get the reason for failure.
*/
goog.proto2.TextFormatSerializer.Parser.prototype.parse =
function(message, data, opt_ignoreMissingFields) {
this.error_ = null;
this.ignoreMissingFields_ = !!opt_ignoreMissingFields;
this.tokenizer_ = new goog.proto2.TextFormatSerializer.Tokenizer_(data, true);
this.tokenizer_.next();
return this.consumeMessage_(message, '');
};
/**
* @return {?string} The parse error, if any.
*/
goog.proto2.TextFormatSerializer.Parser.prototype.getError = function() {
return this.error_;
};
/**
* Reports a parse error.
* @param {string} msg The error message.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.reportError_ =
function(msg) {
this.error_ = msg;
};
/**
* Attempts to consume the given message.
* @param {goog.proto2.Message} message The message to consume and fill. If
* null, then the message contents will be consumed without ever being set
* to anything.
* @param {string} delimiter The delimiter expected at the end of the message.
* @return {boolean} True on success, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeMessage_ =
function(message, delimiter) {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
while (!this.lookingAt_('>') && !this.lookingAt_('}') &&
!this.lookingAtType_(types.END)) {
if (!this.consumeField_(message)) { return false; }
}
if (delimiter) {
if (!this.consume_(delimiter)) { return false; }
} else {
if (!this.lookingAtType_(types.END)) {
this.reportError_('Expected END token');
}
}
return true;
};
/**
* Attempts to consume the value of the given field.
* @param {goog.proto2.Message} message The parent message.
* @param {goog.proto2.FieldDescriptor} field The field.
* @return {boolean} True on success, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeFieldValue_ =
function(message, field) {
var value = this.getFieldValue_(field);
if (goog.isNull(value)) { return false; }
if (field.isRepeated()) {
message.add(field, value);
} else {
message.set(field, value);
}
return true;
};
/**
* Attempts to convert a string to a number.
* @param {string} num in hexadecimal or float format.
* @return {?number} The converted number or null on error.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.getNumberFromString_ =
function(num) {
var returnValue = goog.string.contains(num, '.') ?
parseFloat(num) : // num is a float.
goog.string.parseInt(num); // num is an int.
goog.asserts.assert(!isNaN(returnValue));
goog.asserts.assert(isFinite(returnValue));
return returnValue;
};
/**
* Parse NaN, positive infinity, or negative infinity from a string.
* @param {string} identifier An identifier string to check.
* @return {?number} Infinity, negative infinity, NaN, or null if none
* of the constants could be parsed.
* @private.
*/
goog.proto2.TextFormatSerializer.Parser.parseNumericalConstant_ =
function(identifier) {
if (/^-?inf(?:inity)?f?$/i.test(identifier)) {
return Infinity * (goog.string.startsWith(identifier, '-') ? -1 : 1);
}
if (/^nanf?$/i.test(identifier)) {
return NaN;
}
return null;
};
/**
* Attempts to parse the given field's value from the stream.
* @param {goog.proto2.FieldDescriptor} field The field.
* @return {*} The field's value or null if none.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.getFieldValue_ =
function(field) {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
switch (field.getFieldType()) {
case goog.proto2.FieldDescriptor.FieldType.DOUBLE:
case goog.proto2.FieldDescriptor.FieldType.FLOAT:
var identifier = this.consumeIdentifier_();
if (identifier) {
var numericalIdentifier =
goog.proto2.TextFormatSerializer.Parser.parseNumericalConstant_(
identifier);
// Use isDefAndNotNull since !!NaN is false.
if (goog.isDefAndNotNull(numericalIdentifier)) {
return numericalIdentifier;
}
}
case goog.proto2.FieldDescriptor.FieldType.INT32:
case goog.proto2.FieldDescriptor.FieldType.UINT32:
case goog.proto2.FieldDescriptor.FieldType.FIXED32:
case goog.proto2.FieldDescriptor.FieldType.SFIXED32:
case goog.proto2.FieldDescriptor.FieldType.SINT32:
var num = this.consumeNumber_();
if (!num) { return null; }
return goog.proto2.TextFormatSerializer.Parser.getNumberFromString_(num);
case goog.proto2.FieldDescriptor.FieldType.INT64:
case goog.proto2.FieldDescriptor.FieldType.UINT64:
case goog.proto2.FieldDescriptor.FieldType.FIXED64:
case goog.proto2.FieldDescriptor.FieldType.SFIXED64:
case goog.proto2.FieldDescriptor.FieldType.SINT64:
var num = this.consumeNumber_();
if (!num) { return null; }
if (field.getNativeType() == Number) {
// 64-bit number stored as a number.
return goog.proto2.TextFormatSerializer.Parser.getNumberFromString_(
num);
}
return num; // 64-bit numbers are by default stored as strings.
case goog.proto2.FieldDescriptor.FieldType.BOOL:
var ident = this.consumeIdentifier_();
if (!ident) { return null; }
switch (ident) {
case 'true': return true;
case 'false': return false;
default:
this.reportError_('Unknown type for bool: ' + ident);
return null;
}
case goog.proto2.FieldDescriptor.FieldType.ENUM:
if (this.lookingAtType_(types.NUMBER)) {
return this.consumeNumber_();
} else {
// Search the enum type for a matching key.
var name = this.consumeIdentifier_();
if (!name) {
return null;
}
var enumValue = field.getNativeType()[name];
if (enumValue == null) {
this.reportError_('Unknown enum value: ' + name);
return null;
}
return enumValue;
}
case goog.proto2.FieldDescriptor.FieldType.BYTES:
case goog.proto2.FieldDescriptor.FieldType.STRING:
return this.consumeString_();
}
};
/**
* Attempts to consume a nested message.
* @param {goog.proto2.Message} message The parent message.
* @param {goog.proto2.FieldDescriptor} field The field.
* @return {boolean} True on success, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeNestedMessage_ =
function(message, field) {
var delimiter = '';
// Messages support both < > and { } as delimiters for legacy reasons.
if (this.tryConsume_('<')) {
delimiter = '>';
} else {
if (!this.consume_('{')) { return false; }
delimiter = '}';
}
var msg = field.getFieldMessageType().createMessageInstance();
var result = this.consumeMessage_(msg, delimiter);
if (!result) { return false; }
// Add the message to the parent message.
if (field.isRepeated()) {
message.add(field, msg);
} else {
message.set(field, msg);
}
return true;
};
/**
* Attempts to consume the value of an unknown field. This method uses
* heuristics to try to consume just the right tokens.
* @return {boolean} True on success, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeUnknownFieldValue_ =
function() {
// : is optional.
this.tryConsume_(':');
// Handle form: [.. , ... , ..]
if (this.tryConsume_('[')) {
while (true) {
this.tokenizer_.next();
if (this.tryConsume_(']')) {
break;
}
if (!this.consume_(',')) { return false; }
}
return true;
}
// Handle nested messages/groups.
if (this.tryConsume_('<')) {
return this.consumeMessage_(null /* unknown */, '>');
} else if (this.tryConsume_('{')) {
return this.consumeMessage_(null /* unknown */, '}');
} else {
// Otherwise, consume a single token for the field value.
this.tokenizer_.next();
}
return true;
};
/**
* Attempts to consume a field under a message.
* @param {goog.proto2.Message} message The parent message. If null, then the
* field value will be consumed without being assigned to anything.
* @return {boolean} True on success, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeField_ =
function(message) {
var fieldName = this.consumeIdentifier_();
if (!fieldName) {
this.reportError_('Missing field name');
return false;
}
var field = null;
if (message) {
field = message.getDescriptor().findFieldByName(fieldName.toString());
}
if (field == null) {
if (this.ignoreMissingFields_) {
return this.consumeUnknownFieldValue_();
} else {
this.reportError_('Unknown field: ' + fieldName);
return false;
}
}
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.MESSAGE ||
field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.GROUP) {
// : is optional here.
this.tryConsume_(':');
if (!this.consumeNestedMessage_(message, field)) { return false; }
} else {
// Long Format: "someField: 123"
// Short Format: "someField: [123, 456, 789]"
if (!this.consume_(':')) { return false; }
if (field.isRepeated() && this.tryConsume_('[')) {
// Short repeated format, e.g. "foo: [1, 2, 3]"
while (true) {
if (!this.consumeFieldValue_(message, field)) { return false; }
if (this.tryConsume_(']')) {
break;
}
if (!this.consume_(',')) { return false; }
}
} else {
// Normal field format.
if (!this.consumeFieldValue_(message, field)) { return false; }
}
}
// For historical reasons, fields may optionally be separated by commas or
// semicolons.
this.tryConsume_(',') || this.tryConsume_(';');
return true;
};
/**
* Attempts to consume a token with the given string value.
* @param {string} value The string value for the token.
* @return {boolean} True if the token matches and was consumed, false
* otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.tryConsume_ =
function(value) {
if (this.lookingAt_(value)) {
this.tokenizer_.next();
return true;
}
return false;
};
/**
* Consumes a token of the given type.
* @param {goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes} type The type
* of the token to consume.
* @return {?string} The string value of the token or null on error.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeToken_ =
function(type) {
if (!this.lookingAtType_(type)) {
this.reportError_('Expected token type: ' + type);
return null;
}
var value = this.tokenizer_.getCurrent().value;
this.tokenizer_.next();
return value;
};
/**
* Consumes an IDENTIFIER token.
* @return {?string} The string value or null on error.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeIdentifier_ =
function() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
return this.consumeToken_(types.IDENTIFIER);
};
/**
* Consumes a NUMBER token.
* @return {?string} The string value or null on error.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeNumber_ =
function() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
return this.consumeToken_(types.NUMBER);
};
/**
* Consumes a STRING token.
* @return {?string} The *deescaped* string value or null on error.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consumeString_ =
function() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
var value = this.consumeToken_(types.STRING);
if (!value) {
return null;
}
return goog.json.parse(value).toString();
};
/**
* Consumes a token with the given value. If not found, reports an error.
* @param {string} value The string value expected for the token.
* @return {boolean} True on success, false otherwise.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.consume_ = function(value) {
if (!this.tryConsume_(value)) {
this.reportError_('Expected token "' + value + '"');
return false;
}
return true;
};
/**
* @param {string} value The value to check against.
* @return {boolean} True if the current token has the given string value.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.lookingAt_ =
function(value) {
return this.tokenizer_.getCurrent().value == value;
};
/**
* @param {goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes} type The
* token type.
* @return {boolean} True if the current token has the given type.
* @private
*/
goog.proto2.TextFormatSerializer.Parser.prototype.lookingAtType_ =
function(type) {
return this.tokenizer_.getCurrent().type == type;
};

View File

@@ -0,0 +1,629 @@
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Unit tests for goog.proto2.TextFormatSerializer.
*
*/
/** @suppress {extraProvide} */
goog.provide('goog.proto2.TextFormatSerializerTest');
goog.require('goog.proto2.TextFormatSerializer');
goog.require('goog.testing.jsunit');
goog.require('proto2.TestAllTypes');
goog.setTestOnly('goog.proto2.TextFormatSerializerTest');
function testSerialization() {
var message = new proto2.TestAllTypes();
// Set the fields.
// Singular.
message.setOptionalInt32(101);
message.setOptionalUint32(103);
message.setOptionalSint32(105);
message.setOptionalFixed32(107);
message.setOptionalSfixed32(109);
message.setOptionalInt64('102');
message.setOptionalFloat(111.5);
message.setOptionalDouble(112.5);
message.setOptionalBool(true);
message.setOptionalString('test');
message.setOptionalBytes('abcd');
var group = new proto2.TestAllTypes.OptionalGroup();
group.setA(111);
message.setOptionalgroup(group);
var nestedMessage = new proto2.TestAllTypes.NestedMessage();
nestedMessage.setB(112);
message.setOptionalNestedMessage(nestedMessage);
message.setOptionalNestedEnum(proto2.TestAllTypes.NestedEnum.FOO);
// Repeated.
message.addRepeatedInt32(201);
message.addRepeatedInt32(202);
// Serialize to a simplified text format.
var simplified = new goog.proto2.TextFormatSerializer().serialize(message);
var expected = 'optional_int32: 101\n' +
'optional_int64: 102\n' +
'optional_uint32: 103\n' +
'optional_sint32: 105\n' +
'optional_fixed32: 107\n' +
'optional_sfixed32: 109\n' +
'optional_float: 111.5\n' +
'optional_double: 112.5\n' +
'optional_bool: true\n' +
'optional_string: "test"\n' +
'optional_bytes: "abcd"\n' +
'optionalgroup {\n' +
' a: 111\n' +
'}\n' +
'optional_nested_message {\n' +
' b: 112\n' +
'}\n' +
'optional_nested_enum: FOO\n' +
'repeated_int32: 201\n' +
'repeated_int32: 202\n';
assertEquals(expected, simplified);
}
function testSerializationOfUnknown() {
var nestedUnknown = new proto2.TestAllTypes();
var message = new proto2.TestAllTypes();
// Set the fields.
// Known.
message.setOptionalInt32(101);
message.addRepeatedInt32(201);
message.addRepeatedInt32(202);
nestedUnknown.addRepeatedInt32(301);
nestedUnknown.addRepeatedInt32(302);
// Unknown.
message.setUnknown(1000, 301);
message.setUnknown(1001, 302);
message.setUnknown(1002, 'hello world');
message.setUnknown(1002, nestedUnknown);
nestedUnknown.setUnknown(2000, 401);
// Serialize.
var simplified = new goog.proto2.TextFormatSerializer().serialize(message);
var expected = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'repeated_int32: 202\n' +
'1000: 301\n' +
'1001: 302\n' +
'1002 {\n' +
' repeated_int32: 301\n' +
' repeated_int32: 302\n' +
' 2000: 401\n' +
'}';
assertEquals(expected, simplified);
}
/**
* Asserts that the given string value parses into the given set of tokens.
* @param {string} value The string value to parse.
* @param {Array.<Object> | Object} tokens The tokens to check against. If not
* an array, a single token is expected.
* @param {boolean=} opt_ignoreWhitespace Whether whitespace tokens should be
* skipped by the tokenizer.
*/
function assertTokens(value, tokens, opt_ignoreWhitespace) {
var tokenizer = new goog.proto2.TextFormatSerializer.Tokenizer_(
value, opt_ignoreWhitespace);
var tokensFound = [];
while (tokenizer.next()) {
tokensFound.push(tokenizer.getCurrent());
}
if (goog.typeOf(tokens) != 'array') {
tokens = [tokens];
}
assertEquals(tokens.length, tokensFound.length);
for (var i = 0; i < tokens.length; ++i) {
assertToken(tokens[i], tokensFound[i]);
}
}
function assertToken(expected, found) {
assertEquals(expected.type, found.type);
if (expected.value) {
assertEquals(expected.value, found.value);
}
}
function testTokenizer() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens('{ 123 }', [
{ type: types.OPEN_BRACE },
{ type: types.WHITESPACE, value: ' ' },
{ type: types.NUMBER, value: '123' },
{ type: types.WHITESPACE, value: ' '},
{ type: types.CLOSE_BRACE }
]);
}
function testTokenizerNoWhitespace() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens('{ "hello world" }', [
{ type: types.OPEN_BRACE },
{ type: types.STRING, value: '"hello world"' },
{ type: types.CLOSE_BRACE }
], true);
}
function assertIdentifier(identifier) {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens(identifier, { type: types.IDENTIFIER, value: identifier });
}
function assertComment(comment) {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens(comment, { type: types.COMMENT, value: comment });
}
function assertString(str) {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens(str, { type: types.STRING, value: str });
}
function assertNumber(num) {
num = num.toString();
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens(num, { type: types.NUMBER, value: num });
}
function testTokenizerSingleTokens() {
var types = goog.proto2.TextFormatSerializer.Tokenizer_.TokenTypes;
assertTokens('{', { type: types.OPEN_BRACE });
assertTokens('}', { type: types.CLOSE_BRACE });
assertTokens('<', { type: types.OPEN_TAG });
assertTokens('>', { type: types.CLOSE_TAG });
assertTokens(':', { type: types.COLON });
assertTokens(',', { type: types.COMMA });
assertTokens(';', { type: types.SEMI });
assertIdentifier('abcd');
assertIdentifier('Abcd');
assertIdentifier('ABcd');
assertIdentifier('ABcD');
assertIdentifier('a123nc');
assertIdentifier('a45_bC');
assertIdentifier('A45_bC');
assertIdentifier('inf');
assertIdentifier('infinity');
assertIdentifier('nan');
assertNumber(0);
assertNumber(10);
assertNumber(123);
assertNumber(1234);
assertNumber(123.56);
assertNumber(-124);
assertNumber(-1234);
assertNumber(-123.56);
assertNumber('123f');
assertNumber('123.6f');
assertNumber('-123f');
assertNumber('-123.8f');
assertNumber('0x1234');
assertNumber('0x12ac34');
assertNumber('0x49e281db686fb');
assertString('""');
assertString('"hello world"');
assertString('"hello # world"');
assertString('"hello #\\" world"');
assertString('"|"');
assertString('"\\"\\""');
assertString('"\\"foo\\""');
assertString('"\\"foo\\" and \\"bar\\""');
assertString('"foo \\"and\\" bar"');
assertComment('# foo bar baz');
assertComment('# foo ## bar baz');
assertComment('# foo "bar" baz');
}
function testSerializationOfStringWithQuotes() {
var nestedUnknown = new proto2.TestAllTypes();
var message = new proto2.TestAllTypes();
message.setOptionalString('hello "world"');
// Serialize.
var simplified = new goog.proto2.TextFormatSerializer().serialize(message);
var expected = 'optional_string: "hello \\"world\\""\n';
assertEquals(expected, simplified);
}
function testDeserialization() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'repeated_int32: 202\n' +
'optional_float: 123.4';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(101, message.getOptionalInt32());
assertEquals(201, message.getRepeatedInt32(0));
assertEquals(202, message.getRepeatedInt32(1));
assertEquals(123.4, message.getOptionalFloat());
}
function testDeserializationOfList() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: [201, 202]\n' +
'optional_float: 123.4';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(101, message.getOptionalInt32());
assertEquals(201, message.getRepeatedInt32(0));
assertEquals(123.4, message.getOptionalFloat());
}
function testDeserializationOfIntegerAsHexadecimalString() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 0x1\n' +
'optional_sint32: 0xf\n' +
'optional_uint32: 0xffffffff\n' +
'repeated_int32: [0x0, 0xff]\n';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(1, message.getOptionalInt32());
assertEquals(15, message.getOptionalSint32());
assertEquals(4294967295, message.getOptionalUint32());
assertEquals(0, message.getRepeatedInt32(0));
assertEquals(255, message.getRepeatedInt32(1));
}
function testDeserializationOfInt64AsHexadecimalString() {
var message = new proto2.TestAllTypes();
var value = 'optional_int64: 0xf';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals('0xf', message.getOptionalInt64());
}
function testDeserializationOfZeroFalseAndEmptyString() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 0\n' +
'optional_bool: false\n' +
'optional_string: ""';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(0, message.getOptionalInt32());
assertEquals(false, message.getOptionalBool());
assertEquals('', message.getOptionalString());
}
function testDeserializationSkipUnknown() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'some_unknown: true\n' +
'repeated_int32: 202\n' +
'optional_float: 123.4';
var parser = new goog.proto2.TextFormatSerializer.Parser();
assertTrue(parser.parse(message, value, true));
assertEquals(101, message.getOptionalInt32());
assertEquals(201, message.getRepeatedInt32(0));
assertEquals(202, message.getRepeatedInt32(1));
assertEquals(123.4, message.getOptionalFloat());
}
function testDeserializationSkipUnknownList() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'some_unknown: [true, 1, 201, "hello"]\n' +
'repeated_int32: 202\n' +
'optional_float: 123.4';
var parser = new goog.proto2.TextFormatSerializer.Parser();
assertTrue(parser.parse(message, value, true));
assertEquals(101, message.getOptionalInt32());
assertEquals(201, message.getRepeatedInt32(0));
assertEquals(202, message.getRepeatedInt32(1));
assertEquals(123.4, message.getOptionalFloat());
}
function testDeserializationSkipUnknownNested() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'some_unknown: <\n' +
' a: 1\n' +
' b: 2\n' +
'>\n' +
'repeated_int32: 202\n' +
'optional_float: 123.4';
var parser = new goog.proto2.TextFormatSerializer.Parser();
assertTrue(parser.parse(message, value, true));
assertEquals(101, message.getOptionalInt32());
assertEquals(201, message.getRepeatedInt32(0));
assertEquals(202, message.getRepeatedInt32(1));
assertEquals(123.4, message.getOptionalFloat());
}
function testDeserializationSkipUnknownNestedInvalid() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'some_unknown: <\n' +
' a: \n' + // Missing value.
' b: 2\n' +
'>\n' +
'repeated_int32: 202\n' +
'optional_float: 123.4';
var parser = new goog.proto2.TextFormatSerializer.Parser();
assertFalse(parser.parse(message, value, true));
}
function testDeserializationSkipUnknownNestedInvalid2() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'repeated_int32: 201\n' +
'some_unknown: <\n' +
' a: 2\n' +
' b: 2\n' +
'}\n' + // Delimiter mismatch
'repeated_int32: 202\n' +
'optional_float: 123.4';
var parser = new goog.proto2.TextFormatSerializer.Parser();
assertFalse(parser.parse(message, value, true));
}
function testDeserializationLegacyFormat() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101,\n' +
'repeated_int32: 201,\n' +
'repeated_int32: 202;\n' +
'optional_float: 123.4';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(101, message.getOptionalInt32());
assertEquals(201, message.getRepeatedInt32(0));
assertEquals(202, message.getRepeatedInt32(1));
assertEquals(123.4, message.getOptionalFloat());
}
function testDeserializationVariedNumbers() {
var message = new proto2.TestAllTypes();
var value = (
'repeated_int32: 23\n' +
'repeated_int32: -3\n' +
'repeated_int32: 0xdeadbeef\n' +
'repeated_float: 123.0\n' +
'repeated_float: -3.27\n' +
'repeated_float: -35.5f\n'
);
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(23, message.getRepeatedInt32(0));
assertEquals(-3, message.getRepeatedInt32(1));
assertEquals(3735928559, message.getRepeatedInt32(2));
assertEquals(123.0, message.getRepeatedFloat(0));
assertEquals(-3.27, message.getRepeatedFloat(1));
assertEquals(-35.5, message.getRepeatedFloat(2));
}
function testParseNumericalConstant() {
var parseNumericalConstant =
goog.proto2.TextFormatSerializer.Parser.parseNumericalConstant_;
assertEquals(Infinity, parseNumericalConstant('inf'));
assertEquals(Infinity, parseNumericalConstant('inff'));
assertEquals(Infinity, parseNumericalConstant('infinity'));
assertEquals(Infinity, parseNumericalConstant('infinityf'));
assertEquals(Infinity, parseNumericalConstant('Infinityf'));
assertEquals(-Infinity, parseNumericalConstant('-inf'));
assertEquals(-Infinity, parseNumericalConstant('-inff'));
assertEquals(-Infinity, parseNumericalConstant('-infinity'));
assertEquals(-Infinity, parseNumericalConstant('-infinityf'));
assertEquals(-Infinity, parseNumericalConstant('-Infinity'));
assertNull(parseNumericalConstant('-infin'));
assertNull(parseNumericalConstant('infin'));
assertNull(parseNumericalConstant('-infinite'));
assertNull(parseNumericalConstant('-infin'));
assertNull(parseNumericalConstant('infin'));
assertNull(parseNumericalConstant('-infinite'));
assertTrue(isNaN(parseNumericalConstant('Nan')));
assertTrue(isNaN(parseNumericalConstant('NaN')));
assertTrue(isNaN(parseNumericalConstant('NAN')));
assertTrue(isNaN(parseNumericalConstant('nan')));
assertTrue(isNaN(parseNumericalConstant('nanf')));
assertTrue(isNaN(parseNumericalConstant('NaNf')));
assertEquals(Number.POSITIVE_INFINITY, parseNumericalConstant('infinity'));
assertEquals(Number.NEGATIVE_INFINITY, parseNumericalConstant('-inf'));
assertEquals(Number.NEGATIVE_INFINITY, parseNumericalConstant('-infinity'));
assertNull(parseNumericalConstant('na'));
assertNull(parseNumericalConstant('-nan'));
assertNull(parseNumericalConstant('none'));
}
function testDeserializationOfNumericalConstants() {
var message = new proto2.TestAllTypes();
var value = (
'repeated_float: inf\n' +
'repeated_float: -inf\n' +
'repeated_float: nan\n' +
'repeated_float: 300.2\n'
);
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(Infinity, message.getRepeatedFloat(0));
assertEquals(-Infinity, message.getRepeatedFloat(1));
assertTrue(isNaN(message.getRepeatedFloat(2)));
assertEquals(300.2, message.getRepeatedFloat(3));
}
function testGetNumberFromString() {
var getNumberFromString =
goog.proto2.TextFormatSerializer.Parser.getNumberFromString_;
assertEquals(3735928559, getNumberFromString('0xdeadbeef'));
assertEquals(4276215469, getNumberFromString('0xFEE1DEAD'));
assertEquals(123.1, getNumberFromString('123.1'));
assertEquals(123.0, getNumberFromString('123.0'));
assertEquals(-29.3, getNumberFromString('-29.3f'));
assertEquals(23, getNumberFromString('23'));
assertEquals(-3, getNumberFromString('-3'));
assertEquals(-3.27, getNumberFromString('-3.27'));
assertThrows(goog.partial(getNumberFromString, 'cat'));
assertThrows(goog.partial(getNumberFromString, 'NaN'));
assertThrows(goog.partial(getNumberFromString, 'inf'));
}
function testDeserializationError() {
var message = new proto2.TestAllTypes();
var value = 'optional_int33: 101\n';
var result =
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(result, 'Unknown field: optional_int33');
}
function testNestedDeserialization() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'optional_nested_message: {\n' +
' b: 301\n' +
'}';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(101, message.getOptionalInt32());
assertEquals(301, message.getOptionalNestedMessage().getB());
}
function testNestedDeserializationLegacyFormat() {
var message = new proto2.TestAllTypes();
var value = 'optional_int32: 101\n' +
'optional_nested_message: <\n' +
' b: 301\n' +
'>';
new goog.proto2.TextFormatSerializer().deserializeTo(message, value);
assertEquals(101, message.getOptionalInt32());
assertEquals(301, message.getOptionalNestedMessage().getB());
}
function testBidirectional() {
var message = new proto2.TestAllTypes();
// Set the fields.
// Singular.
message.setOptionalInt32(101);
message.setOptionalInt64('102');
message.setOptionalUint32(103);
message.setOptionalUint64('104');
message.setOptionalSint32(105);
message.setOptionalSint64('106');
message.setOptionalFixed32(107);
message.setOptionalFixed64('108');
message.setOptionalSfixed32(109);
message.setOptionalSfixed64('110');
message.setOptionalFloat(111.5);
message.setOptionalDouble(112.5);
message.setOptionalBool(true);
message.setOptionalString('test');
message.setOptionalBytes('abcd');
var group = new proto2.TestAllTypes.OptionalGroup();
group.setA(111);
message.setOptionalgroup(group);
var nestedMessage = new proto2.TestAllTypes.NestedMessage();
nestedMessage.setB(112);
message.setOptionalNestedMessage(nestedMessage);
message.setOptionalNestedEnum(proto2.TestAllTypes.NestedEnum.FOO);
// Repeated.
message.addRepeatedInt32(201);
message.addRepeatedInt32(202);
message.addRepeatedString('hello "world"');
// Serialize the message to text form.
var serializer = new goog.proto2.TextFormatSerializer();
var textform = serializer.serialize(message);
// Create a copy and deserialize into the copy.
var copy = new proto2.TestAllTypes();
serializer.deserializeTo(copy, textform);
// Assert that the messages are structurally equivalent.
assertTrue(copy.equals(message));
}
function testBidirectional64BitNumber() {
var message = new proto2.TestAllTypes();
message.setOptionalInt64Number(10000000);
message.setOptionalInt64String('200000000000000000');
// Serialize the message to text form.
var serializer = new goog.proto2.TextFormatSerializer();
var textform = serializer.serialize(message);
// Create a copy and deserialize into the copy.
var copy = new proto2.TestAllTypes();
serializer.deserializeTo(copy, textform);
// Assert that the messages are structurally equivalent.
assertTrue(copy.equals(message));
}

View File

@@ -0,0 +1,54 @@
// Copyright 2009 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Utility methods for Protocol Buffer 2 implementation.
*/
goog.provide('goog.proto2.Util');
goog.require('goog.asserts');
/**
* @define {boolean} Defines a PBCHECK constant that can be turned off by
* clients of PB2. This for is clients that do not want assertion/checking
* running even in non-COMPILED builds.
*/
goog.define('goog.proto2.Util.PBCHECK', !COMPILED);
/**
* Asserts that the given condition is true, if and only if the PBCHECK
* flag is on.
*
* @param {*} condition The condition to check.
* @param {string=} opt_message Error message in case of failure.
* @throws {Error} Assertion failed, the condition evaluates to false.
*/
goog.proto2.Util.assert = function(condition, opt_message) {
if (goog.proto2.Util.PBCHECK) {
goog.asserts.assert(condition, opt_message);
}
};
/**
* Returns true if debug assertions (checks) are on.
*
* @return {boolean} The value of the PBCHECK constant.
*/
goog.proto2.Util.conductChecks = function() {
return goog.proto2.Util.PBCHECK;
};