From cb16f29952aacb8fe12be32c0322506a92b947df Mon Sep 17 00:00:00 2001 From: David Freese Date: Thu, 6 Feb 2025 10:53:14 -0800 Subject: [PATCH] Add Merge to prototext.UnmarshalOptions This adds a Merge option to prototext.UnmarshalOptions to match proto.UnmarshalOptions. This is particularly useful when needing to read multiple textproto files of the same format that wrap a single repeated field. I've added this to the exact same position in the UnmarshalOptions struct as the proto version. It can be moved to the bottom of the struct definition if that would cause backwards compatibility issues, but I wasn't aware of any. --- encoding/prototext/decode.go | 9 ++++++++- encoding/prototext/decode_test.go | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/encoding/prototext/decode.go b/encoding/prototext/decode.go index b53805056..75289948b 100644 --- a/encoding/prototext/decode.go +++ b/encoding/prototext/decode.go @@ -31,6 +31,11 @@ func Unmarshal(b []byte, m proto.Message) error { type UnmarshalOptions struct { pragma.NoUnkeyedLiterals + // Merge merges the input into the destination message. + // The default behavior is to always reset the message before unmarshaling, + // unless Merge is specified. + Merge bool + // AllowPartial accepts input for messages that will result in missing // required fields. If AllowPartial is false (the default), Unmarshal will // return error if there are any missing required fields. @@ -62,7 +67,9 @@ func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error { // For profiling purposes, avoid changing the name of this function or // introducing other code paths for unmarshal that do not go through this. func (o UnmarshalOptions) unmarshal(b []byte, m proto.Message) error { - proto.Reset(m) + if !o.Merge { + proto.Reset(m) + } if o.Resolver == nil { o.Resolver = protoregistry.GlobalTypes diff --git a/encoding/prototext/decode_test.go b/encoding/prototext/decode_test.go index 7fc90ca53..41d3c6f41 100644 --- a/encoding/prototext/decode_test.go +++ b/encoding/prototext/decode_test.go @@ -1288,6 +1288,26 @@ str_to_nested: { inputMessage: &pb2.Nests{}, inputText: "reserved_field: 'ignore this'", wantMessage: &pb2.Nests{}, + }, { + desc: "reset message when merge is not set", + inputMessage: &pb3.Scalars{ + SBool: true, + }, + inputText: `s_string: "abc"`, + wantMessage: &pb3.Scalars{ + SString: "abc", + }, + }, { + desc: "message not reset when merge is enabled", + umo: prototext.UnmarshalOptions{Merge: true}, + inputMessage: &pb3.Scalars{ + SBool: true, + }, + inputText: `s_string: "abc"`, + wantMessage: &pb3.Scalars{ + SBool: true, + SString: "abc", + }, }, { desc: "extensions of non-repeated fields", inputMessage: &pb2.Extensions{},