proto: Add CloneOf[M Message](m M) M This allows writing: `copy := proto.CloneOf(orig)` instead of the previous: `copy := proto.Clone(orig).(*pb.MyMessage)` Fixes golang/protobuf#1594 Change-Id: I7b8b712b6e59607ccc339720ee3c146e8a7ea28b Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/653536 Reviewed-by: Cassondra Foesch <cfoesch@gmail.com> Reviewed-by: Michael Stapelberg <stapelberg@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/proto/merge.go b/proto/merge.go index 3c6fe57..ef55b97 100644 --- a/proto/merge.go +++ b/proto/merge.go
@@ -59,6 +59,12 @@ return dst.Interface() } +// CloneOf returns a deep copy of m. If the top-level message is invalid, +// it returns an invalid message as well. +func CloneOf[M Message](m M) M { + return Clone(m).(M) +} + // mergeOptions provides a namespace for merge functions, and can be // exported in the future if we add user-visible merge options. type mergeOptions struct{}
diff --git a/proto/merge_test.go b/proto/merge_test.go index 05978cb..2cdc1b7 100644 --- a/proto/merge_test.go +++ b/proto/merge_test.go
@@ -853,6 +853,16 @@ } } +func TestCloneOf(t *testing.T) { + want := &testpb.TestAllTypes{ + OptionalInt32: proto.Int32(1), + } + got := proto.CloneOf(want) + if !proto.Equal(got, want) { + t.Errorf("Clone(src) != src:\n got %v\nwant %v", got, want) + } +} + // mutateValue changes a Value, returning a new value. // // For scalar values, it returns a value different from the input.