Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions protobuf/lib/meta.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,13 @@ const GeneratedMessage_reservedNames = <String>[
'isFrozen',
'isInitialized',
'mergeFromBuffer',
'mergeFromBufferFrozen',
'mergeFromCodedBufferReader',
'mergeFromCodedBufferReaderFrozen',
'mergeFromJson',
'mergeFromJsonFrozen',
'mergeFromJsonMap',
'mergeFromJsonMapFrozen',
'mergeFromMessage',
'mergeFromProto3Json',
'mergeUnknownFields',
Expand Down
87 changes: 57 additions & 30 deletions protobuf/lib/src/protobuf/coded_buffer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,15 @@ void _writeToCodedBufferWriter(_FieldSet fs, CodedBufferWriter out) {
}

void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
CodedBufferReader input, ExtensionRegistry registry) {
CodedBufferReader input, ExtensionRegistry registry, bool frozen) {
ArgumentError.checkNotNull(registry);
fs._ensureWritable();
while (true) {
var tag = input.readTag();
if (tag == 0) return;
if (tag == 0) {
fs._frozenState = frozen;
return;
}
var wireType = tag & 0x7;
var tagNumber = tag >> 3;

Expand All @@ -44,6 +47,7 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,

if (fi == null || !_wireTypeMatches(fi.type, wireType)) {
if (!fs._ensureUnknownFields().mergeFieldFromBuffer(tag, input)) {
fs._frozenState = frozen;
return;
}
continue;
Expand Down Expand Up @@ -128,83 +132,100 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
}
break;
case PbFieldType._REPEATED_BOOL:
_readPackable(meta, fs, input, wireType, fi, input.readBool);
_readPackable(meta, fs, input, wireType, fi, input.readBool, frozen);
break;
case PbFieldType._REPEATED_BYTES:
fs
._ensureRepeatedField(meta, fi)
.add(Uint8List.fromList(input.readBytes()));
var list = fs._ensureRepeatedField(meta, fi);
list.add(Uint8List.fromList(input.readBytes()));
if (list is PbList) {
list._isReadOnly = frozen;
}
break;
case PbFieldType._REPEATED_STRING:
fs._ensureRepeatedField(meta, fi).add(input.readString());
var list = fs._ensureRepeatedField(meta, fi);
list.add(input.readString());
if (list is PbList) {
list._isReadOnly = frozen;
}
break;
case PbFieldType._REPEATED_FLOAT:
_readPackable(meta, fs, input, wireType, fi, input.readFloat);
_readPackable(meta, fs, input, wireType, fi, input.readFloat, frozen);
break;
case PbFieldType._REPEATED_DOUBLE:
_readPackable(meta, fs, input, wireType, fi, input.readDouble);
_readPackable(meta, fs, input, wireType, fi, input.readDouble, frozen);
break;
case PbFieldType._REPEATED_ENUM:
_readPackableToListEnum(
meta, fs, input, wireType, fi, tagNumber, registry);
meta, fs, input, wireType, fi, tagNumber, registry, frozen);
break;
case PbFieldType._REPEATED_GROUP:
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
input.readGroup(tagNumber, subMessage, registry);
fs._ensureRepeatedField(meta, fi).add(subMessage);
var list = fs._ensureRepeatedField(meta, fi);
list.add(subMessage);
if (list is PbList) {
list._isReadOnly = frozen;
}
break;
case PbFieldType._REPEATED_INT32:
_readPackable(meta, fs, input, wireType, fi, input.readInt32);
_readPackable(meta, fs, input, wireType, fi, input.readInt32, frozen);
break;
case PbFieldType._REPEATED_INT64:
_readPackable(meta, fs, input, wireType, fi, input.readInt64);
_readPackable(meta, fs, input, wireType, fi, input.readInt64, frozen);
break;
case PbFieldType._REPEATED_SINT32:
_readPackable(meta, fs, input, wireType, fi, input.readSint32);
_readPackable(meta, fs, input, wireType, fi, input.readSint32, frozen);
break;
case PbFieldType._REPEATED_SINT64:
_readPackable(meta, fs, input, wireType, fi, input.readSint64);
_readPackable(meta, fs, input, wireType, fi, input.readSint64, frozen);
break;
case PbFieldType._REPEATED_UINT32:
_readPackable(meta, fs, input, wireType, fi, input.readUint32);
_readPackable(meta, fs, input, wireType, fi, input.readUint32, frozen);
break;
case PbFieldType._REPEATED_UINT64:
_readPackable(meta, fs, input, wireType, fi, input.readUint64);
_readPackable(meta, fs, input, wireType, fi, input.readUint64, frozen);
break;
case PbFieldType._REPEATED_FIXED32:
_readPackable(meta, fs, input, wireType, fi, input.readFixed32);
_readPackable(meta, fs, input, wireType, fi, input.readFixed32, frozen);
break;
case PbFieldType._REPEATED_FIXED64:
_readPackable(meta, fs, input, wireType, fi, input.readFixed64);
_readPackable(meta, fs, input, wireType, fi, input.readFixed64, frozen);
break;
case PbFieldType._REPEATED_SFIXED32:
_readPackable(meta, fs, input, wireType, fi, input.readSfixed32);
_readPackable(
meta, fs, input, wireType, fi, input.readSfixed32, frozen);
break;
case PbFieldType._REPEATED_SFIXED64:
_readPackable(meta, fs, input, wireType, fi, input.readSfixed64);
_readPackable(
meta, fs, input, wireType, fi, input.readSfixed64, frozen);
break;
case PbFieldType._REPEATED_MESSAGE:
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
input.readMessage(subMessage, registry);
fs._ensureRepeatedField(meta, fi).add(subMessage);
var list = fs._ensureRepeatedField(meta, fi);
list.add(subMessage);
if (list is PbList) {
list._isReadOnly = frozen;
}
break;
case PbFieldType._MAP:
final mapFieldInfo = fi as MapFieldInfo;
final mapEntryMeta = mapFieldInfo.mapEntryBuilderInfo;
fs
._ensureMapField(meta, mapFieldInfo)
._mergeEntry(mapEntryMeta, input, registry);
var map = fs._ensureMapField(meta, mapFieldInfo);
map._mergeEntry(mapEntryMeta, input, registry);
map._isReadonly = frozen;
break;
default:
throw 'Unknown field type $fieldType';
}
}
fs._frozenState = frozen;
}

void _readPackable(BuilderInfo meta, _FieldSet fs, CodedBufferReader input,
int wireType, FieldInfo fi, Function() readFunc) {
int wireType, FieldInfo fi, Function() readFunc, bool frozen) {
void readToList(List list) => list.add(readFunc());
_readPackableToList(meta, fs, input, wireType, fi, readToList);
_readPackableToList(meta, fs, input, wireType, fi, readToList, frozen);
}

void _readPackableToListEnum(
Expand All @@ -214,7 +235,8 @@ void _readPackableToListEnum(
int wireType,
FieldInfo fi,
int tagNumber,
ExtensionRegistry registry) {
ExtensionRegistry registry,
bool frozen) {
void readToList(List list) {
var rawValue = input.readEnum();
var value = meta._decodeEnum(tagNumber, registry, rawValue);
Expand All @@ -226,7 +248,7 @@ void _readPackableToListEnum(
}
}

_readPackableToList(meta, fs, input, wireType, fi, readToList);
_readPackableToList(meta, fs, input, wireType, fi, readToList, frozen);
}

void _readPackableToList(
Expand All @@ -235,7 +257,8 @@ void _readPackableToList(
CodedBufferReader input,
int wireType,
FieldInfo fi,
Function(List) readToList) {
Function(List) readToList,
bool frozen) {
var list = fs._ensureRepeatedField(meta, fi);

if (wireType == WIRETYPE_LENGTH_DELIMITED) {
Expand All @@ -249,4 +272,8 @@ void _readPackableToList(
// Not packed.
readToList(list);
}

if (list is PbList) {
list._isReadOnly = frozen;
}
}
86 changes: 82 additions & 4 deletions protobuf/lib/src/protobuf/generated_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,37 @@ abstract class GeneratedMessage {
void writeToCodedBufferWriter(CodedBufferWriter output) =>
_writeToCodedBufferWriter(_fieldSet, output);

/// 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 mergeFromCodedBufferReader(CodedBufferReader input,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
final meta = _fieldSet._meta;
_mergeFromCodedBufferReader(meta, _fieldSet, input, extensionRegistry);
_mergeFromCodedBufferReader(
meta, _fieldSet, input, extensionRegistry, false);
}

/// 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.
///
/// NOTE: Sub-messages that are already part of this message are not marked as
/// read-only.
void mergeFromCodedBufferReaderFrozen(CodedBufferReader input,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
final meta = _fieldSet._meta;
_mergeFromCodedBufferReader(
meta, _fieldSet, input, extensionRegistry, true);
}

/// Merges serialized protocol buffer data into this message.
Expand All @@ -189,7 +216,28 @@ abstract class GeneratedMessage {
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
var codedInput = CodedBufferReader(input);
final meta = _fieldSet._meta;
_mergeFromCodedBufferReader(meta, _fieldSet, codedInput, extensionRegistry);
_mergeFromCodedBufferReader(
meta, _fieldSet, codedInput, extensionRegistry, false);
codedInput.checkLastTagWas(0);
}

/// Merges serialized protocol buffer data into this message and makes it read-only.
///
/// 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.
///
/// NOTE: Sub-messages that are already part of this message are not marked as
/// read-only.
void mergeFromBufferFrozen(List<int> input,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
var codedInput = CodedBufferReader(input);
final meta = _fieldSet._meta;
_mergeFromCodedBufferReader(
meta, _fieldSet, codedInput, extensionRegistry, true);
codedInput.checkLastTagWas(0);
}

Expand Down Expand Up @@ -279,7 +327,25 @@ abstract class GeneratedMessage {
/// on the Dart VM for a slight speedup.
final Map<String, dynamic> jsonMap =
jsonDecode(data, reviver: _emptyReviver);
_mergeFromJsonMap(_fieldSet, jsonMap, extensionRegistry);
_mergeFromJsonMap(_fieldSet, jsonMap, extensionRegistry, false);
}

/// Merges field values from [data], a JSON object, encoded as described by
/// [GeneratedMessage.writeToJson] and marks the message read-only.
///
/// For the proto3 JSON format use: [mergeFromProto3Json].
///
/// NOTE: Sub-messages that are already part of this message are not marked as
/// read-only.
void mergeFromJsonFrozen(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 Map<String, dynamic> jsonMap =
jsonDecode(data, reviver: _emptyReviver);
_mergeFromJsonMap(_fieldSet, jsonMap, extensionRegistry, true);
}

static Object? _emptyReviver(Object? k, Object? v) => v;
Expand All @@ -289,7 +355,19 @@ abstract class GeneratedMessage {
/// The encoding is described in [GeneratedMessage.writeToJson].
void mergeFromJsonMap(Map<String, dynamic> json,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
_mergeFromJsonMap(_fieldSet, json, extensionRegistry);
_mergeFromJsonMap(_fieldSet, json, extensionRegistry, false);
}

/// Merges field values from a JSON object represented as a Dart map
/// and marks the message read-only.
///
/// The encoding is described in [GeneratedMessage.writeToJson].
///
/// NOTE: Sub-messages that are already part of this message are not marked as
/// read-only.
void mergeFromJsonMapFrozen(Map<String, dynamic> json,
[ExtensionRegistry extensionRegistry = ExtensionRegistry.EMPTY]) {
_mergeFromJsonMap(_fieldSet, json, extensionRegistry, true);
}

/// Adds an extension field value to a repeated field.
Expand Down
21 changes: 13 additions & 8 deletions protobuf/lib/src/protobuf/json.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ Map<String, dynamic> _writeToJsonMap(_FieldSet fs) {

// Merge fields from a previously decoded JSON object.
// (Called recursively on nested messages.)
void _mergeFromJsonMap(
_FieldSet fs, Map<String, dynamic> json, ExtensionRegistry? registry) {
void _mergeFromJsonMap(_FieldSet fs, Map<String, dynamic> json,
ExtensionRegistry? registry, bool frozen) {
fs._ensureWritable();
final keys = json.keys;
final meta = fs._meta;
Expand All @@ -107,18 +107,19 @@ void _mergeFromJsonMap(
if (fi == null) continue; // Unknown tag; skip
}
if (fi.isMapField) {
_appendJsonMap(
meta, fs, json[key], fi as MapFieldInfo<dynamic, dynamic>, registry);
_appendJsonMap(meta, fs, json[key], fi as MapFieldInfo<dynamic, dynamic>,
registry, frozen);
} else if (fi.isRepeated) {
_appendJsonList(meta, fs, json[key], fi, registry);
_appendJsonList(meta, fs, json[key], fi, registry, frozen);
} else {
_setJsonField(meta, fs, json[key], fi, registry);
}
}
fs._frozenState = frozen;
}

void _appendJsonList(BuilderInfo meta, _FieldSet fs, List jsonList,
FieldInfo fi, ExtensionRegistry? registry) {
FieldInfo fi, ExtensionRegistry? registry, bool frozen) {
final repeated = fi._ensureRepeatedField(meta, fs);
// Micro optimization. Using "for in" generates the following and iterator
// alloc:
Expand All @@ -134,10 +135,13 @@ void _appendJsonList(BuilderInfo meta, _FieldSet fs, List jsonList,
convertedValue ??= fi.defaultEnumValue;
repeated.add(convertedValue);
}
if (repeated is PbList) {
repeated._isReadOnly = frozen;
}
}

void _appendJsonMap(BuilderInfo meta, _FieldSet fs, List jsonList,
MapFieldInfo fi, ExtensionRegistry? registry) {
MapFieldInfo fi, ExtensionRegistry? registry, bool frozen) {
final entryMeta = fi.mapEntryBuilderInfo;
final map = fi._ensureMapField(meta, fs) as PbMap<dynamic, dynamic>;
for (var jsonEntryDynamic in jsonList) {
Expand All @@ -163,6 +167,7 @@ void _appendJsonMap(BuilderInfo meta, _FieldSet fs, List jsonList,
convertedValue ??= fi.defaultEnumValue;
map[convertedKey] = convertedValue;
}
map._isReadonly = frozen;
}

void _setJsonField(BuilderInfo meta, _FieldSet fs, json, FieldInfo fi,
Expand Down Expand Up @@ -279,7 +284,7 @@ dynamic _convertJsonValue(BuilderInfo meta, _FieldSet fs, value, int tagNumber,
if (value is Map) {
final messageValue = value as Map<String, dynamic>;
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
_mergeFromJsonMap(subMessage._fieldSet, messageValue, registry);
_mergeFromJsonMap(subMessage._fieldSet, messageValue, registry, false);
return subMessage;
}
expectedType = 'nested message or group';
Expand Down
3 changes: 2 additions & 1 deletion protobuf/lib/src/protobuf/pb_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ class PbMap<K, V> extends MapBase<K, V> {
var oldLimit = input._currentLimit;
input._currentLimit = input._bufferPos + length;
final entryFieldSet = _FieldSet(null, mapEntryMeta, null);
_mergeFromCodedBufferReader(mapEntryMeta, entryFieldSet, input, registry);
_mergeFromCodedBufferReader(
mapEntryMeta, entryFieldSet, input, registry, false);
input.checkLastTagWas(0);
input._currentLimit = oldLimit;
var key =
Expand Down
Loading