| // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of protobuf; |
| |
| typedef GeneratedMessage CreateBuilderFunc(); |
| typedef MakeDefaultFunc(); |
| typedef ProtobufEnum ValueOfFunc(int value); |
| |
| /// The base class for all protobuf message types. |
| /// |
| /// The protoc plugin generates subclasses providing type-specific |
| /// properties and methods. |
| /// |
| /// Public properties and methods added here should also be added to |
| /// GeneratedMessage_reservedNames and should be unlikely to be used in |
| /// a proto file. |
| abstract class GeneratedMessage { |
| _FieldSet _fieldSet; |
| |
| GeneratedMessage() { |
| _fieldSet = new _FieldSet(this, info_, eventPlugin); |
| if (eventPlugin != null) eventPlugin.attach(this); |
| } |
| |
| GeneratedMessage.fromBuffer( |
| List<int> input, ExtensionRegistry extensionRegistry) { |
| _fieldSet = new _FieldSet(this, info_, eventPlugin); |
| if (eventPlugin != null) eventPlugin.attach(this); |
| mergeFromBuffer(input, extensionRegistry); |
| } |
| |
| GeneratedMessage.fromJson(String input, ExtensionRegistry extensionRegistry) { |
| _fieldSet = new _FieldSet(this, info_, eventPlugin); |
| if (eventPlugin != null) eventPlugin.attach(this); |
| mergeFromJson(input, extensionRegistry); |
| } |
| |
| // Overridden by subclasses. |
| BuilderInfo get info_; |
| |
| /// Subclasses can override this getter to be notified of changes |
| /// to protobuf fields. |
| EventPlugin get eventPlugin => null; |
| |
| /// Creates a deep copy of the fields in this message. |
| /// (The generated code uses [mergeFromMessage].) |
| GeneratedMessage clone(); |
| |
| UnknownFieldSet get unknownFields => _fieldSet._ensureUnknownFields(); |
| |
| bool get _isReadOnly => this is ReadonlyMessageMixin; |
| |
| bool hasRequiredFields() => info_.hasRequiredFields; |
| |
| /// Returns [:true:] if all required fields in the message and all embedded |
| /// messages are set, false otherwise. |
| bool isInitialized() => _fieldSet._hasRequiredValues(); |
| |
| /// Clears all data that was set in this message. |
| /// |
| /// After calling [clear], [getField] will still return default values for |
| /// unset fields. |
| void clear() => _fieldSet._clear(); |
| |
| // TODO(antonm): move to getters. |
| int getTagNumber(String fieldName) => info_.tagNumber(fieldName); |
| |
| bool operator ==(other) { |
| if (identical(this, other)) return true; |
| return other is GeneratedMessage |
| ? _fieldSet._equals(other._fieldSet) |
| : false; |
| } |
| |
| /// Calculates a hash code based on the contents of the protobuf. |
| /// |
| /// The hash may change when any field changes (recursively). |
| /// Therefore, protobufs used as map keys shouldn't be changed. |
| int get hashCode => _fieldSet._hashCode; |
| |
| /// Returns a String representation of this message. |
| /// |
| /// This representation is similar to, but not quite, the Protocol Buffer |
| /// TextFormat. Each field is printed on its own line. Sub-messages are |
| /// indented two spaces farther than their parent messages. |
| /// |
| /// Note that this format is absolutely subject to change, and should only |
| /// ever be used for debugging. |
| String toString() => toDebugString(); |
| |
| /// Returns a String representation of this message. |
| /// |
| /// This generates the same output as [toString], but can be used by mixins |
| /// to compose debug strings with additional information. |
| String toDebugString() { |
| var out = new StringBuffer(); |
| _fieldSet.writeString(out, ''); |
| return out.toString(); |
| } |
| |
| void check() { |
| if (!isInitialized()) { |
| List<String> invalidFields = <String>[]; |
| _fieldSet._appendInvalidFields(invalidFields, ""); |
| String missingFields = (invalidFields..sort()).join(', '); |
| throw new StateError('Message missing required fields: $missingFields'); |
| } |
| } |
| |
| Uint8List writeToBuffer() { |
| CodedBufferWriter out = new CodedBufferWriter(); |
| writeToCodedBufferWriter(out); |
| return out.toBuffer(); |
| } |
| |
| void writeToCodedBufferWriter(CodedBufferWriter output) => |
| _writeToCodedBufferWriter(_fieldSet, output); |
| |
| void mergeFromCodedBufferReader(CodedBufferReader input, |
| [ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) => |
| _mergeFromCodedBufferReader(_fieldSet, input, extensionRegistry); |
| |
| /// Merges serialized protocol buffer data into this message. |
| /// |
| /// For each field in [input] that is already present in this message: |
| /// |
| /// * If it's a repeated field, this appends to the end of our list. |
| /// * Else, if it's a scalar, this overwrites our field. |
| /// * Else, (it's a non-repeated sub-message), this recursively merges into |
| /// the existing sub-message. |
| void mergeFromBuffer(List<int> input, |
| [ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) { |
| CodedBufferReader codedInput = new CodedBufferReader(input); |
| _mergeFromCodedBufferReader(_fieldSet, codedInput, extensionRegistry); |
| codedInput.checkLastTagWas(0); |
| } |
| |
| // JSON support. |
| |
| /// Returns the JSON encoding of this message as a Dart [Map]. |
| /// |
| /// The encoding is described in [GeneratedMessage.writeToJson]. |
| Map<String, dynamic> writeToJsonMap() => _writeToJsonMap(_fieldSet); |
| |
| /// Returns a JSON string that encodes this message. |
| /// |
| /// Each message (top level or nested) is represented as an object delimited |
| /// by curly braces. Within a message, elements are indexed by tag number |
| /// (surrounded by quotes). Repeated elements are represented as arrays. |
| /// |
| /// Boolean values, strings, and floating-point values are represented as |
| /// literals. Values with a 32-bit integer datatype are represented as integer |
| /// literals; values with a 64-bit integer datatype (regardless of their |
| /// actual runtime value) are represented as strings. Enumerated values are |
| /// represented as their integer value. |
| String writeToJson() => jsonEncode(writeToJsonMap()); |
| |
| /// Merges field values from [data], a JSON object, encoded as described by |
| /// [GeneratedMessage.writeToJson]. |
| void mergeFromJson(String data, |
| [ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) { |
| /// Disable lazy creation of Dart objects for a dart2js speedup. |
| /// This is a slight regression on the Dart VM. |
| /// TODO(skybrian) we could skip the reviver if we're running |
| /// on the Dart VM for a slight speedup. |
| final jsonMap = |
| jsonDecode(data, reviver: _emptyReviver) as Map<String, dynamic>; |
| _mergeFromJsonMap(_fieldSet, jsonMap, extensionRegistry); |
| } |
| |
| static _emptyReviver(k, v) => v; |
| |
| /// Merges field values from a JSON object represented as a Dart map. |
| /// |
| /// The encoding is described in [GeneratedMessage.writeToJson]. |
| void mergeFromJsonMap(Map<String, dynamic> json, |
| [ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) { |
| _mergeFromJsonMap(_fieldSet, json, extensionRegistry); |
| } |
| |
| /// Adds an extension field value to a repeated field. |
| /// |
| /// The backing [List] will be created if necessary. |
| /// If the list already exists, the old extension won't be overwritten. |
| void addExtension(Extension extension, var value) { |
| if (!extension.isRepeated) { |
| throw new ArgumentError( |
| 'Cannot add to a non-repeated field (use setExtension())'); |
| } |
| _fieldSet._ensureExtensions().._ensureRepeatedField(extension).add(value); |
| } |
| |
| /// Clears an extension field and also removes the extension. |
| void clearExtension(Extension extension) { |
| if (_fieldSet._hasExtensions) { |
| _fieldSet._extensions._clearFieldAndInfo(extension); |
| } |
| } |
| |
| /// Clears the contents of a given field. |
| /// |
| /// If it's an extension field, the Extension will be kept. |
| /// The tagNumber should be a valid tag or extension. |
| void clearField(int tagNumber) => _fieldSet._clearField(tagNumber); |
| |
| bool extensionsAreInitialized() => _fieldSet._hasRequiredExtensionValues(); |
| |
| /// Returns the value of [extension]. |
| /// |
| /// If not set, returns the extension's default value. |
| getExtension(Extension extension) { |
| if (_isReadOnly) return extension.readonlyDefault; |
| return _fieldSet._ensureExtensions()._getFieldOrDefault(extension); |
| } |
| |
| /// Returns the value of the field associated with [tagNumber], or the |
| /// default value if it is not set. |
| getField(int tagNumber) => _fieldSet._getField(tagNumber); |
| |
| /// Creates List implementing a mutable repeated field. |
| /// |
| /// Mixins may override this method to change the List type. To ensure |
| /// that the protobuf can be encoded correctly, the returned List must |
| /// validate all items added to it. This can most easily be done |
| /// using the FieldInfo.check function. |
| List<T> createRepeatedField<T>(int tagNumber, FieldInfo<T> fi) { |
| return new PbList<T>(check: fi.check); |
| } |
| |
| /// Returns the value of a field, ignoring any defaults. |
| /// |
| /// For unset or cleared fields, returns null. |
| /// Also returns null for unknown tag numbers. |
| getFieldOrNull(int tagNumber) => _fieldSet._getFieldOrNullByTag(tagNumber); |
| |
| /// Returns the default value for the given field. |
| /// |
| /// For repeated fields, returns an immutable empty list |
| /// (unlike [getField]). For all other fields, returns |
| /// the same thing that getField() would for a cleared field. |
| getDefaultForField(int tagNumber) => |
| _fieldSet._ensureInfo(tagNumber).readonlyDefault; |
| |
| /// Returns [:true:] if a value of [extension] is present. |
| bool hasExtension(Extension extension) => |
| _fieldSet._hasExtensions && |
| _fieldSet._extensions._getFieldOrNull(extension) != null; |
| |
| /// Returns [:true:] if this message has a field associated with [tagNumber]. |
| bool hasField(int tagNumber) => _fieldSet._hasField(tagNumber); |
| |
| /// Merges the contents of the [other] into this message. |
| /// |
| /// Singular fields that are set in [other] overwrite the corresponding fields |
| /// in this message. Repeated fields are appended. Singular sub-messages are |
| /// recursively merged. |
| void mergeFromMessage(GeneratedMessage other) => |
| _fieldSet._mergeFromMessage(other._fieldSet); |
| |
| void mergeUnknownFields(UnknownFieldSet unknownFieldSet) => _fieldSet |
| ._ensureUnknownFields() |
| .mergeFromUnknownFieldSet(unknownFieldSet); |
| |
| /// Sets the value of a non-repeated extension field to [value]. |
| void setExtension(Extension extension, value) { |
| if (value == null) throw new ArgumentError('value is null'); |
| if (_isRepeated(extension.type)) { |
| throw new ArgumentError(_fieldSet._setFieldFailedMessage( |
| extension, value, 'repeating field (use get + .add())')); |
| } |
| _fieldSet._ensureExtensions()._setFieldAndInfo(extension, value); |
| } |
| |
| /// Sets the value of a field by its [tagNumber]. |
| /// |
| /// Throws an [:ArgumentError:] if [value] does not match the type |
| /// associated with [tagNumber]. |
| /// |
| /// Throws an [:ArgumentError:] if [value] is [:null:]. To clear a field of |
| /// it's current value, use [clearField] instead. |
| void setField(int tagNumber, value) { |
| _fieldSet._setField(tagNumber, value); |
| return; // ignore: dead_code |
| return; // ignore: dead_code |
| } |
| |
| /// For generated code only. |
| T $_get<T>(int index, T defaultValue) => |
| _fieldSet._$get<T>(index, defaultValue); |
| |
| /// For generated code only. |
| T $_getN<T>(int index) => _fieldSet._$getN<T>(index); |
| |
| /// For generated code only. |
| List<T> $_getList<T>(int index) => _fieldSet._$getList<T>(index); |
| |
| /// For generated code only. |
| String $_getS(int index, String defaultValue) => |
| _fieldSet._$getS(index, defaultValue); |
| |
| /// For generated code only. |
| Int64 $_getI64(int index) => _fieldSet._$getI64(index); |
| |
| /// For generated code only. |
| bool $_has(int index) => _fieldSet._$has(index); |
| |
| /// For generated code only. |
| void $_setBool(int index, bool value) => _fieldSet._$set(index, value); |
| |
| /// For generated code only. |
| void $_setBytes(int index, List<int> value) => _fieldSet._$set(index, value); |
| |
| /// For generated code only. |
| void $_setString(int index, String value) => _fieldSet._$set(index, value); |
| |
| /// For generated code only. |
| void $_setFloat(int index, double value) { |
| if (value == null || !_isFloat32(value)) { |
| _fieldSet._$check(index, value); |
| } |
| _fieldSet._$set(index, value); |
| } |
| |
| /// For generated code only. |
| void $_setDouble(int index, double value) => _fieldSet._$set(index, value); |
| |
| /// For generated code only. |
| void $_setSignedInt32(int index, int value) { |
| if (value == null || !_isSigned32(value)) { |
| _fieldSet._$check(index, value); |
| } |
| _fieldSet._$set(index, value); |
| } |
| |
| /// For generated code only. |
| void $_setUnsignedInt32(int index, int value) { |
| if (value == null || !_isUnsigned32(value)) { |
| _fieldSet._$check(index, value); |
| } |
| _fieldSet._$set(index, value); |
| } |
| |
| /// For generated code only. |
| void $_setInt64(int index, Int64 value) => _fieldSet._$set(index, value); |
| } |