[ObjC] Add api to add a field to another collection of unknown fields.
PiperOrigin-RevId: 663424215
diff --git a/objectivec/GPBUnknownFields.h b/objectivec/GPBUnknownFields.h
index 07a7af5..859614b 100644
--- a/objectivec/GPBUnknownFields.h
+++ b/objectivec/GPBUnknownFields.h
@@ -110,6 +110,23 @@
- (nonnull GPBUnknownFields *)addGroupWithFieldNumber:(int32_t)fieldNumber;
/**
+ * Add the copy of the given unknown field.
+ *
+ * This can be useful from processing one `GPBUnknownFields` to create another.
+ *
+ * NOTE: If the field being copied is an Group, this instance added is new and thus
+ * the `.group` of that result is also new, so if you intent is to modify the group
+ * it *must* be fetched out of the result.
+ *
+ * It is a programming error to call this when the `type` is a legacy field.
+ *
+ * @param field The field to add.
+ *
+ * @return The autoreleased field that was added.
+ **/
+- (GPBUnknownField *)addCopyOfField:(nonnull GPBUnknownField *)field;
+
+/**
* Removes the given field from the set.
*
* It is a programming error to attempt to remove a field that is not in this collection.
diff --git a/objectivec/GPBUnknownFields.m b/objectivec/GPBUnknownFields.m
index 890be42..dc004b3 100644
--- a/objectivec/GPBUnknownFields.m
+++ b/objectivec/GPBUnknownFields.m
@@ -323,6 +323,16 @@
return [group autorelease];
}
+- (GPBUnknownField *)addCopyOfField:(nonnull GPBUnknownField *)field {
+ if (field->type_ == GPBUnknownFieldTypeLegacy) {
+ [NSException raise:NSInternalInconsistencyException
+ format:@"GPBUnknownField is the wrong type"];
+ }
+ GPBUnknownField *result = [field copy];
+ [fields_ addObject:result];
+ return [result autorelease];
+}
+
- (void)removeField:(nonnull GPBUnknownField *)field {
NSUInteger count = fields_.count;
[fields_ removeObjectIdenticalTo:field];
diff --git a/objectivec/Tests/GPBUnknownFieldsTest.m b/objectivec/Tests/GPBUnknownFieldsTest.m
index c73e064..2b8a085 100644
--- a/objectivec/Tests/GPBUnknownFieldsTest.m
+++ b/objectivec/Tests/GPBUnknownFieldsTest.m
@@ -662,6 +662,37 @@
XCTAssertEqual(loop, 10);
}
+- (void)testAddCopyOfField {
+ GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease];
+ [ufs addFieldNumber:1 varint:10];
+ [ufs addFieldNumber:2 fixed32:11];
+ [ufs addFieldNumber:3 fixed64:12];
+ [ufs addFieldNumber:4 lengthDelimited:DataFromCStr("foo")];
+ GPBUnknownFields* group = [ufs addGroupWithFieldNumber:5];
+ [group addFieldNumber:10 varint:100];
+ GPBUnknownFields* subGroup = [group addGroupWithFieldNumber:100];
+ [subGroup addFieldNumber:50 varint:50];
+
+ GPBUnknownFields* ufs2 = [[[GPBUnknownFields alloc] init] autorelease];
+ for (GPBUnknownField* field in ufs) {
+ GPBUnknownField* field2 = [ufs2 addCopyOfField:field];
+ XCTAssertEqualObjects(field, field2);
+ if (field.type == GPBUnknownFieldTypeGroup) {
+ // Group does a copy because the `.group` value is mutable.
+ XCTAssertTrue(field != field2); // Pointer comparison.
+ XCTAssertTrue(group != field2.group); // Pointer comparison.
+ XCTAssertEqualObjects(group, field2.group);
+ GPBUnknownFields* subGroupAdded = [field2.group firstGroup:100];
+ XCTAssertTrue(subGroupAdded != subGroup); // Pointer comparison.
+ XCTAssertEqualObjects(subGroupAdded, subGroup);
+ } else {
+ // All other types are immutable, so they use the same object.
+ XCTAssertTrue(field == field2); // Pointer comparision.
+ }
+ }
+ XCTAssertEqualObjects(ufs, ufs2);
+}
+
- (void)testDescriptions {
// Exercise description for completeness.
GPBUnknownFields* ufs = [[[GPBUnknownFields alloc] init] autorelease];