Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expect same message types in mergeFromMessage #661

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
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
88 changes: 41 additions & 47 deletions protobuf/lib/src/protobuf/field_set.dart
Original file line number Diff line number Diff line change
Expand Up @@ -719,26 +719,37 @@ class _FieldSet {

/// 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.
/// Singular fields that are set in [other] overwrite the corresponding
/// fields in this message. Repeated fields are appended. Singular
/// sub-messages are recursively merged.
///
/// Messages are expected to have the same [BuilderInfo].
///
/// Throws [ArgumentError] when the messages don't have the same
/// [BuilderInfo].
void _mergeFromMessage(_FieldSet other) {
// TODO(https://github.com/google/protobuf.dart/issues/60): Recognize
// when `this` and [other] are the same protobuf (e.g. from cloning). In
// this case, we can merge the non-extension fields without field lookups or
// validation checks.
_ensureWritable();

if (!identical(_meta, other._meta)) {
throw ArgumentError(
'Merging messages with different types (BuilderInfos)');
}

for (var fi in other._infosSortedByTag) {
var value = other._values[fi.index!];
if (value != null) _mergeField(fi, value, isExtension: false);
if (value != null) {
_mergeField(fi, value, isExtension: false);
}
}

final otherExtensions = other._extensions;
if (otherExtensions != null) {
for (var tagNumber in otherExtensions._tagNumbers) {
var extension = otherExtensions._getInfoOrNull(tagNumber)!;
var value = otherExtensions._getFieldOrNull(extension);
_mergeField(extension, value, isExtension: true);
if (value != null) {
_mergeField(extension, value, isExtension: true);
}
}
}

Expand All @@ -748,29 +759,15 @@ class _FieldSet {
}
}

void _mergeField(FieldInfo otherFi, fieldValue, {required bool isExtension}) {
final tagNumber = otherFi.tagNumber;

// Determine the FieldInfo to use.
// Don't allow regular fields to be overwritten by extensions.
final meta = _meta;
var fi = _nonExtensionInfo(meta, tagNumber);
if (fi == null && isExtension) {
// This will overwrite any existing extension field info.
fi = otherFi;
}

if (fi!.isMapField) {
if (fieldValue == null) {
return;
}
final MapFieldInfo<dynamic, dynamic> f = fi as dynamic;
final PbMap<dynamic, dynamic> map =
f._ensureMapField(meta, this) as dynamic;
if (_isGroupOrMessage(f.valueFieldType)) {
PbMap fieldValueMap = fieldValue;
void _mergeField(FieldInfo fi, fieldValue, {required bool isExtension}) {
if (fi.isMapField) {
final MapFieldInfo<dynamic, dynamic> mapInfo = fi as dynamic;
final map = mapInfo._ensureMapField(_meta, this);
if (_isGroupOrMessage(mapInfo.valueFieldType)) {
final Map fieldValueMap = fieldValue;
for (final entry in fieldValueMap.entries) {
map[entry.key] = (entry.value as GeneratedMessage).deepCopy();
final GeneratedMessage value = entry.value;
map[entry.key] = value.deepCopy();
}
} else {
map.addAll(fieldValue);
Expand All @@ -779,31 +776,29 @@ class _FieldSet {
}

if (fi.isRepeated) {
if (_isGroupOrMessage(otherFi.type)) {
// fieldValue must be a PbList of GeneratedMessage.
PbList<GeneratedMessage> pbList = fieldValue;
var repeatedFields = fi._ensureRepeatedField(meta, this);
for (var i = 0; i < pbList.length; ++i) {
repeatedFields.add(pbList[i].deepCopy());
if (_isGroupOrMessage(fi.type)) {
final List<GeneratedMessage> list = fieldValue;
final repeatedFields = fi._ensureRepeatedField(_meta, this);
for (var i = 0; i < list.length; ++i) {
repeatedFields.add(list[i].deepCopy());
}
} else {
// fieldValue must be at least a PbList.
PbList pbList = fieldValue;
fi._ensureRepeatedField(meta, this).addAll(pbList);
final List list = fieldValue;
fi._ensureRepeatedField(_meta, this).addAll(list);
}
return;
}

if (otherFi.isGroupOrMessage) {
final currentFi = isExtension
if (fi.isGroupOrMessage) {
final currentFieldValue = isExtension
? _ensureExtensions()._getFieldOrNull(fi as Extension<dynamic>)
: _values[fi.index!];

GeneratedMessage msg = fieldValue;
if (currentFi == null) {
final GeneratedMessage msg = fieldValue;
if (currentFieldValue == null) {
fieldValue = msg.deepCopy();
} else {
final GeneratedMessage currentMsg = currentFi;
final GeneratedMessage currentMsg = currentFieldValue;
fieldValue = currentMsg..mergeFromMessage(msg);
}
}
Expand All @@ -812,8 +807,7 @@ class _FieldSet {
_ensureExtensions()
._setFieldAndInfo(fi as Extension<dynamic>, fieldValue);
} else {
_validateField(fi, fieldValue);
_setNonExtensionFieldUnchecked(meta, fi, fieldValue);
_setNonExtensionFieldUnchecked(_meta, fi, fieldValue);
}
}

Expand Down
5 changes: 5 additions & 0 deletions protobuf/lib/src/protobuf/generated_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@ abstract class GeneratedMessage {
/// Singular fields that are set in [other] overwrite the corresponding fields
/// in this message. Repeated fields are appended. Singular sub-messages are
/// recursively merged.
///
/// Messages are expected to have the same [BuilderInfo].
///
/// Throws [ArgumentError] when the messages don't have the same
/// [BuilderInfo].
@pragma('dart2js:noInline')
void mergeFromMessage(GeneratedMessage other) =>
_fieldSet._mergeFromMessage(other._fieldSet);
Expand Down