xref: /aosp_15_r20/external/golang-protobuf/encoding/prototext/encode.go (revision 1c12ee1efe575feb122dbf939ff15148a3b3e8f2)
1*1c12ee1eSDan Willemsen// Copyright 2018 The Go Authors. All rights reserved.
2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style
3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file.
4*1c12ee1eSDan Willemsen
5*1c12ee1eSDan Willemsenpackage prototext
6*1c12ee1eSDan Willemsen
7*1c12ee1eSDan Willemsenimport (
8*1c12ee1eSDan Willemsen	"fmt"
9*1c12ee1eSDan Willemsen	"strconv"
10*1c12ee1eSDan Willemsen	"unicode/utf8"
11*1c12ee1eSDan Willemsen
12*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/protowire"
13*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/encoding/messageset"
14*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/encoding/text"
15*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/errors"
16*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/flags"
17*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/genid"
18*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/order"
19*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/pragma"
20*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/internal/strs"
21*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/proto"
22*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
23*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoregistry"
24*1c12ee1eSDan Willemsen)
25*1c12ee1eSDan Willemsen
26*1c12ee1eSDan Willemsenconst defaultIndent = "  "
27*1c12ee1eSDan Willemsen
28*1c12ee1eSDan Willemsen// Format formats the message as a multiline string.
29*1c12ee1eSDan Willemsen// This function is only intended for human consumption and ignores errors.
30*1c12ee1eSDan Willemsen// Do not depend on the output being stable. It may change over time across
31*1c12ee1eSDan Willemsen// different versions of the program.
32*1c12ee1eSDan Willemsenfunc Format(m proto.Message) string {
33*1c12ee1eSDan Willemsen	return MarshalOptions{Multiline: true}.Format(m)
34*1c12ee1eSDan Willemsen}
35*1c12ee1eSDan Willemsen
36*1c12ee1eSDan Willemsen// Marshal writes the given proto.Message in textproto format using default
37*1c12ee1eSDan Willemsen// options. Do not depend on the output being stable. It may change over time
38*1c12ee1eSDan Willemsen// across different versions of the program.
39*1c12ee1eSDan Willemsenfunc Marshal(m proto.Message) ([]byte, error) {
40*1c12ee1eSDan Willemsen	return MarshalOptions{}.Marshal(m)
41*1c12ee1eSDan Willemsen}
42*1c12ee1eSDan Willemsen
43*1c12ee1eSDan Willemsen// MarshalOptions is a configurable text format marshaler.
44*1c12ee1eSDan Willemsentype MarshalOptions struct {
45*1c12ee1eSDan Willemsen	pragma.NoUnkeyedLiterals
46*1c12ee1eSDan Willemsen
47*1c12ee1eSDan Willemsen	// Multiline specifies whether the marshaler should format the output in
48*1c12ee1eSDan Willemsen	// indented-form with every textual element on a new line.
49*1c12ee1eSDan Willemsen	// If Indent is an empty string, then an arbitrary indent is chosen.
50*1c12ee1eSDan Willemsen	Multiline bool
51*1c12ee1eSDan Willemsen
52*1c12ee1eSDan Willemsen	// Indent specifies the set of indentation characters to use in a multiline
53*1c12ee1eSDan Willemsen	// formatted output such that every entry is preceded by Indent and
54*1c12ee1eSDan Willemsen	// terminated by a newline. If non-empty, then Multiline is treated as true.
55*1c12ee1eSDan Willemsen	// Indent can only be composed of space or tab characters.
56*1c12ee1eSDan Willemsen	Indent string
57*1c12ee1eSDan Willemsen
58*1c12ee1eSDan Willemsen	// EmitASCII specifies whether to format strings and bytes as ASCII only
59*1c12ee1eSDan Willemsen	// as opposed to using UTF-8 encoding when possible.
60*1c12ee1eSDan Willemsen	EmitASCII bool
61*1c12ee1eSDan Willemsen
62*1c12ee1eSDan Willemsen	// allowInvalidUTF8 specifies whether to permit the encoding of strings
63*1c12ee1eSDan Willemsen	// with invalid UTF-8. This is unexported as it is intended to only
64*1c12ee1eSDan Willemsen	// be specified by the Format method.
65*1c12ee1eSDan Willemsen	allowInvalidUTF8 bool
66*1c12ee1eSDan Willemsen
67*1c12ee1eSDan Willemsen	// AllowPartial allows messages that have missing required fields to marshal
68*1c12ee1eSDan Willemsen	// without returning an error. If AllowPartial is false (the default),
69*1c12ee1eSDan Willemsen	// Marshal will return error if there are any missing required fields.
70*1c12ee1eSDan Willemsen	AllowPartial bool
71*1c12ee1eSDan Willemsen
72*1c12ee1eSDan Willemsen	// EmitUnknown specifies whether to emit unknown fields in the output.
73*1c12ee1eSDan Willemsen	// If specified, the unmarshaler may be unable to parse the output.
74*1c12ee1eSDan Willemsen	// The default is to exclude unknown fields.
75*1c12ee1eSDan Willemsen	EmitUnknown bool
76*1c12ee1eSDan Willemsen
77*1c12ee1eSDan Willemsen	// Resolver is used for looking up types when expanding google.protobuf.Any
78*1c12ee1eSDan Willemsen	// messages. If nil, this defaults to using protoregistry.GlobalTypes.
79*1c12ee1eSDan Willemsen	Resolver interface {
80*1c12ee1eSDan Willemsen		protoregistry.ExtensionTypeResolver
81*1c12ee1eSDan Willemsen		protoregistry.MessageTypeResolver
82*1c12ee1eSDan Willemsen	}
83*1c12ee1eSDan Willemsen}
84*1c12ee1eSDan Willemsen
85*1c12ee1eSDan Willemsen// Format formats the message as a string.
86*1c12ee1eSDan Willemsen// This method is only intended for human consumption and ignores errors.
87*1c12ee1eSDan Willemsen// Do not depend on the output being stable. It may change over time across
88*1c12ee1eSDan Willemsen// different versions of the program.
89*1c12ee1eSDan Willemsenfunc (o MarshalOptions) Format(m proto.Message) string {
90*1c12ee1eSDan Willemsen	if m == nil || !m.ProtoReflect().IsValid() {
91*1c12ee1eSDan Willemsen		return "<nil>" // invalid syntax, but okay since this is for debugging
92*1c12ee1eSDan Willemsen	}
93*1c12ee1eSDan Willemsen	o.allowInvalidUTF8 = true
94*1c12ee1eSDan Willemsen	o.AllowPartial = true
95*1c12ee1eSDan Willemsen	o.EmitUnknown = true
96*1c12ee1eSDan Willemsen	b, _ := o.Marshal(m)
97*1c12ee1eSDan Willemsen	return string(b)
98*1c12ee1eSDan Willemsen}
99*1c12ee1eSDan Willemsen
100*1c12ee1eSDan Willemsen// Marshal writes the given proto.Message in textproto format using options in
101*1c12ee1eSDan Willemsen// MarshalOptions object. Do not depend on the output being stable. It may
102*1c12ee1eSDan Willemsen// change over time across different versions of the program.
103*1c12ee1eSDan Willemsenfunc (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
104*1c12ee1eSDan Willemsen	return o.marshal(m)
105*1c12ee1eSDan Willemsen}
106*1c12ee1eSDan Willemsen
107*1c12ee1eSDan Willemsen// marshal is a centralized function that all marshal operations go through.
108*1c12ee1eSDan Willemsen// For profiling purposes, avoid changing the name of this function or
109*1c12ee1eSDan Willemsen// introducing other code paths for marshal that do not go through this.
110*1c12ee1eSDan Willemsenfunc (o MarshalOptions) marshal(m proto.Message) ([]byte, error) {
111*1c12ee1eSDan Willemsen	var delims = [2]byte{'{', '}'}
112*1c12ee1eSDan Willemsen
113*1c12ee1eSDan Willemsen	if o.Multiline && o.Indent == "" {
114*1c12ee1eSDan Willemsen		o.Indent = defaultIndent
115*1c12ee1eSDan Willemsen	}
116*1c12ee1eSDan Willemsen	if o.Resolver == nil {
117*1c12ee1eSDan Willemsen		o.Resolver = protoregistry.GlobalTypes
118*1c12ee1eSDan Willemsen	}
119*1c12ee1eSDan Willemsen
120*1c12ee1eSDan Willemsen	internalEnc, err := text.NewEncoder(o.Indent, delims, o.EmitASCII)
121*1c12ee1eSDan Willemsen	if err != nil {
122*1c12ee1eSDan Willemsen		return nil, err
123*1c12ee1eSDan Willemsen	}
124*1c12ee1eSDan Willemsen
125*1c12ee1eSDan Willemsen	// Treat nil message interface as an empty message,
126*1c12ee1eSDan Willemsen	// in which case there is nothing to output.
127*1c12ee1eSDan Willemsen	if m == nil {
128*1c12ee1eSDan Willemsen		return []byte{}, nil
129*1c12ee1eSDan Willemsen	}
130*1c12ee1eSDan Willemsen
131*1c12ee1eSDan Willemsen	enc := encoder{internalEnc, o}
132*1c12ee1eSDan Willemsen	err = enc.marshalMessage(m.ProtoReflect(), false)
133*1c12ee1eSDan Willemsen	if err != nil {
134*1c12ee1eSDan Willemsen		return nil, err
135*1c12ee1eSDan Willemsen	}
136*1c12ee1eSDan Willemsen	out := enc.Bytes()
137*1c12ee1eSDan Willemsen	if len(o.Indent) > 0 && len(out) > 0 {
138*1c12ee1eSDan Willemsen		out = append(out, '\n')
139*1c12ee1eSDan Willemsen	}
140*1c12ee1eSDan Willemsen	if o.AllowPartial {
141*1c12ee1eSDan Willemsen		return out, nil
142*1c12ee1eSDan Willemsen	}
143*1c12ee1eSDan Willemsen	return out, proto.CheckInitialized(m)
144*1c12ee1eSDan Willemsen}
145*1c12ee1eSDan Willemsen
146*1c12ee1eSDan Willemsentype encoder struct {
147*1c12ee1eSDan Willemsen	*text.Encoder
148*1c12ee1eSDan Willemsen	opts MarshalOptions
149*1c12ee1eSDan Willemsen}
150*1c12ee1eSDan Willemsen
151*1c12ee1eSDan Willemsen// marshalMessage marshals the given protoreflect.Message.
152*1c12ee1eSDan Willemsenfunc (e encoder) marshalMessage(m protoreflect.Message, inclDelims bool) error {
153*1c12ee1eSDan Willemsen	messageDesc := m.Descriptor()
154*1c12ee1eSDan Willemsen	if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
155*1c12ee1eSDan Willemsen		return errors.New("no support for proto1 MessageSets")
156*1c12ee1eSDan Willemsen	}
157*1c12ee1eSDan Willemsen
158*1c12ee1eSDan Willemsen	if inclDelims {
159*1c12ee1eSDan Willemsen		e.StartMessage()
160*1c12ee1eSDan Willemsen		defer e.EndMessage()
161*1c12ee1eSDan Willemsen	}
162*1c12ee1eSDan Willemsen
163*1c12ee1eSDan Willemsen	// Handle Any expansion.
164*1c12ee1eSDan Willemsen	if messageDesc.FullName() == genid.Any_message_fullname {
165*1c12ee1eSDan Willemsen		if e.marshalAny(m) {
166*1c12ee1eSDan Willemsen			return nil
167*1c12ee1eSDan Willemsen		}
168*1c12ee1eSDan Willemsen		// If unable to expand, continue on to marshal Any as a regular message.
169*1c12ee1eSDan Willemsen	}
170*1c12ee1eSDan Willemsen
171*1c12ee1eSDan Willemsen	// Marshal fields.
172*1c12ee1eSDan Willemsen	var err error
173*1c12ee1eSDan Willemsen	order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
174*1c12ee1eSDan Willemsen		if err = e.marshalField(fd.TextName(), v, fd); err != nil {
175*1c12ee1eSDan Willemsen			return false
176*1c12ee1eSDan Willemsen		}
177*1c12ee1eSDan Willemsen		return true
178*1c12ee1eSDan Willemsen	})
179*1c12ee1eSDan Willemsen	if err != nil {
180*1c12ee1eSDan Willemsen		return err
181*1c12ee1eSDan Willemsen	}
182*1c12ee1eSDan Willemsen
183*1c12ee1eSDan Willemsen	// Marshal unknown fields.
184*1c12ee1eSDan Willemsen	if e.opts.EmitUnknown {
185*1c12ee1eSDan Willemsen		e.marshalUnknown(m.GetUnknown())
186*1c12ee1eSDan Willemsen	}
187*1c12ee1eSDan Willemsen
188*1c12ee1eSDan Willemsen	return nil
189*1c12ee1eSDan Willemsen}
190*1c12ee1eSDan Willemsen
191*1c12ee1eSDan Willemsen// marshalField marshals the given field with protoreflect.Value.
192*1c12ee1eSDan Willemsenfunc (e encoder) marshalField(name string, val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
193*1c12ee1eSDan Willemsen	switch {
194*1c12ee1eSDan Willemsen	case fd.IsList():
195*1c12ee1eSDan Willemsen		return e.marshalList(name, val.List(), fd)
196*1c12ee1eSDan Willemsen	case fd.IsMap():
197*1c12ee1eSDan Willemsen		return e.marshalMap(name, val.Map(), fd)
198*1c12ee1eSDan Willemsen	default:
199*1c12ee1eSDan Willemsen		e.WriteName(name)
200*1c12ee1eSDan Willemsen		return e.marshalSingular(val, fd)
201*1c12ee1eSDan Willemsen	}
202*1c12ee1eSDan Willemsen}
203*1c12ee1eSDan Willemsen
204*1c12ee1eSDan Willemsen// marshalSingular marshals the given non-repeated field value. This includes
205*1c12ee1eSDan Willemsen// all scalar types, enums, messages, and groups.
206*1c12ee1eSDan Willemsenfunc (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
207*1c12ee1eSDan Willemsen	kind := fd.Kind()
208*1c12ee1eSDan Willemsen	switch kind {
209*1c12ee1eSDan Willemsen	case protoreflect.BoolKind:
210*1c12ee1eSDan Willemsen		e.WriteBool(val.Bool())
211*1c12ee1eSDan Willemsen
212*1c12ee1eSDan Willemsen	case protoreflect.StringKind:
213*1c12ee1eSDan Willemsen		s := val.String()
214*1c12ee1eSDan Willemsen		if !e.opts.allowInvalidUTF8 && strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
215*1c12ee1eSDan Willemsen			return errors.InvalidUTF8(string(fd.FullName()))
216*1c12ee1eSDan Willemsen		}
217*1c12ee1eSDan Willemsen		e.WriteString(s)
218*1c12ee1eSDan Willemsen
219*1c12ee1eSDan Willemsen	case protoreflect.Int32Kind, protoreflect.Int64Kind,
220*1c12ee1eSDan Willemsen		protoreflect.Sint32Kind, protoreflect.Sint64Kind,
221*1c12ee1eSDan Willemsen		protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
222*1c12ee1eSDan Willemsen		e.WriteInt(val.Int())
223*1c12ee1eSDan Willemsen
224*1c12ee1eSDan Willemsen	case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
225*1c12ee1eSDan Willemsen		protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
226*1c12ee1eSDan Willemsen		e.WriteUint(val.Uint())
227*1c12ee1eSDan Willemsen
228*1c12ee1eSDan Willemsen	case protoreflect.FloatKind:
229*1c12ee1eSDan Willemsen		// Encoder.WriteFloat handles the special numbers NaN and infinites.
230*1c12ee1eSDan Willemsen		e.WriteFloat(val.Float(), 32)
231*1c12ee1eSDan Willemsen
232*1c12ee1eSDan Willemsen	case protoreflect.DoubleKind:
233*1c12ee1eSDan Willemsen		// Encoder.WriteFloat handles the special numbers NaN and infinites.
234*1c12ee1eSDan Willemsen		e.WriteFloat(val.Float(), 64)
235*1c12ee1eSDan Willemsen
236*1c12ee1eSDan Willemsen	case protoreflect.BytesKind:
237*1c12ee1eSDan Willemsen		e.WriteString(string(val.Bytes()))
238*1c12ee1eSDan Willemsen
239*1c12ee1eSDan Willemsen	case protoreflect.EnumKind:
240*1c12ee1eSDan Willemsen		num := val.Enum()
241*1c12ee1eSDan Willemsen		if desc := fd.Enum().Values().ByNumber(num); desc != nil {
242*1c12ee1eSDan Willemsen			e.WriteLiteral(string(desc.Name()))
243*1c12ee1eSDan Willemsen		} else {
244*1c12ee1eSDan Willemsen			// Use numeric value if there is no enum description.
245*1c12ee1eSDan Willemsen			e.WriteInt(int64(num))
246*1c12ee1eSDan Willemsen		}
247*1c12ee1eSDan Willemsen
248*1c12ee1eSDan Willemsen	case protoreflect.MessageKind, protoreflect.GroupKind:
249*1c12ee1eSDan Willemsen		return e.marshalMessage(val.Message(), true)
250*1c12ee1eSDan Willemsen
251*1c12ee1eSDan Willemsen	default:
252*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
253*1c12ee1eSDan Willemsen	}
254*1c12ee1eSDan Willemsen	return nil
255*1c12ee1eSDan Willemsen}
256*1c12ee1eSDan Willemsen
257*1c12ee1eSDan Willemsen// marshalList marshals the given protoreflect.List as multiple name-value fields.
258*1c12ee1eSDan Willemsenfunc (e encoder) marshalList(name string, list protoreflect.List, fd protoreflect.FieldDescriptor) error {
259*1c12ee1eSDan Willemsen	size := list.Len()
260*1c12ee1eSDan Willemsen	for i := 0; i < size; i++ {
261*1c12ee1eSDan Willemsen		e.WriteName(name)
262*1c12ee1eSDan Willemsen		if err := e.marshalSingular(list.Get(i), fd); err != nil {
263*1c12ee1eSDan Willemsen			return err
264*1c12ee1eSDan Willemsen		}
265*1c12ee1eSDan Willemsen	}
266*1c12ee1eSDan Willemsen	return nil
267*1c12ee1eSDan Willemsen}
268*1c12ee1eSDan Willemsen
269*1c12ee1eSDan Willemsen// marshalMap marshals the given protoreflect.Map as multiple name-value fields.
270*1c12ee1eSDan Willemsenfunc (e encoder) marshalMap(name string, mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error {
271*1c12ee1eSDan Willemsen	var err error
272*1c12ee1eSDan Willemsen	order.RangeEntries(mmap, order.GenericKeyOrder, func(key protoreflect.MapKey, val protoreflect.Value) bool {
273*1c12ee1eSDan Willemsen		e.WriteName(name)
274*1c12ee1eSDan Willemsen		e.StartMessage()
275*1c12ee1eSDan Willemsen		defer e.EndMessage()
276*1c12ee1eSDan Willemsen
277*1c12ee1eSDan Willemsen		e.WriteName(string(genid.MapEntry_Key_field_name))
278*1c12ee1eSDan Willemsen		err = e.marshalSingular(key.Value(), fd.MapKey())
279*1c12ee1eSDan Willemsen		if err != nil {
280*1c12ee1eSDan Willemsen			return false
281*1c12ee1eSDan Willemsen		}
282*1c12ee1eSDan Willemsen
283*1c12ee1eSDan Willemsen		e.WriteName(string(genid.MapEntry_Value_field_name))
284*1c12ee1eSDan Willemsen		err = e.marshalSingular(val, fd.MapValue())
285*1c12ee1eSDan Willemsen		if err != nil {
286*1c12ee1eSDan Willemsen			return false
287*1c12ee1eSDan Willemsen		}
288*1c12ee1eSDan Willemsen		return true
289*1c12ee1eSDan Willemsen	})
290*1c12ee1eSDan Willemsen	return err
291*1c12ee1eSDan Willemsen}
292*1c12ee1eSDan Willemsen
293*1c12ee1eSDan Willemsen// marshalUnknown parses the given []byte and marshals fields out.
294*1c12ee1eSDan Willemsen// This function assumes proper encoding in the given []byte.
295*1c12ee1eSDan Willemsenfunc (e encoder) marshalUnknown(b []byte) {
296*1c12ee1eSDan Willemsen	const dec = 10
297*1c12ee1eSDan Willemsen	const hex = 16
298*1c12ee1eSDan Willemsen	for len(b) > 0 {
299*1c12ee1eSDan Willemsen		num, wtype, n := protowire.ConsumeTag(b)
300*1c12ee1eSDan Willemsen		b = b[n:]
301*1c12ee1eSDan Willemsen		e.WriteName(strconv.FormatInt(int64(num), dec))
302*1c12ee1eSDan Willemsen
303*1c12ee1eSDan Willemsen		switch wtype {
304*1c12ee1eSDan Willemsen		case protowire.VarintType:
305*1c12ee1eSDan Willemsen			var v uint64
306*1c12ee1eSDan Willemsen			v, n = protowire.ConsumeVarint(b)
307*1c12ee1eSDan Willemsen			e.WriteUint(v)
308*1c12ee1eSDan Willemsen		case protowire.Fixed32Type:
309*1c12ee1eSDan Willemsen			var v uint32
310*1c12ee1eSDan Willemsen			v, n = protowire.ConsumeFixed32(b)
311*1c12ee1eSDan Willemsen			e.WriteLiteral("0x" + strconv.FormatUint(uint64(v), hex))
312*1c12ee1eSDan Willemsen		case protowire.Fixed64Type:
313*1c12ee1eSDan Willemsen			var v uint64
314*1c12ee1eSDan Willemsen			v, n = protowire.ConsumeFixed64(b)
315*1c12ee1eSDan Willemsen			e.WriteLiteral("0x" + strconv.FormatUint(v, hex))
316*1c12ee1eSDan Willemsen		case protowire.BytesType:
317*1c12ee1eSDan Willemsen			var v []byte
318*1c12ee1eSDan Willemsen			v, n = protowire.ConsumeBytes(b)
319*1c12ee1eSDan Willemsen			e.WriteString(string(v))
320*1c12ee1eSDan Willemsen		case protowire.StartGroupType:
321*1c12ee1eSDan Willemsen			e.StartMessage()
322*1c12ee1eSDan Willemsen			var v []byte
323*1c12ee1eSDan Willemsen			v, n = protowire.ConsumeGroup(num, b)
324*1c12ee1eSDan Willemsen			e.marshalUnknown(v)
325*1c12ee1eSDan Willemsen			e.EndMessage()
326*1c12ee1eSDan Willemsen		default:
327*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", wtype))
328*1c12ee1eSDan Willemsen		}
329*1c12ee1eSDan Willemsen
330*1c12ee1eSDan Willemsen		b = b[n:]
331*1c12ee1eSDan Willemsen	}
332*1c12ee1eSDan Willemsen}
333*1c12ee1eSDan Willemsen
334*1c12ee1eSDan Willemsen// marshalAny marshals the given google.protobuf.Any message in expanded form.
335*1c12ee1eSDan Willemsen// It returns true if it was able to marshal, else false.
336*1c12ee1eSDan Willemsenfunc (e encoder) marshalAny(any protoreflect.Message) bool {
337*1c12ee1eSDan Willemsen	// Construct the embedded message.
338*1c12ee1eSDan Willemsen	fds := any.Descriptor().Fields()
339*1c12ee1eSDan Willemsen	fdType := fds.ByNumber(genid.Any_TypeUrl_field_number)
340*1c12ee1eSDan Willemsen	typeURL := any.Get(fdType).String()
341*1c12ee1eSDan Willemsen	mt, err := e.opts.Resolver.FindMessageByURL(typeURL)
342*1c12ee1eSDan Willemsen	if err != nil {
343*1c12ee1eSDan Willemsen		return false
344*1c12ee1eSDan Willemsen	}
345*1c12ee1eSDan Willemsen	m := mt.New().Interface()
346*1c12ee1eSDan Willemsen
347*1c12ee1eSDan Willemsen	// Unmarshal bytes into embedded message.
348*1c12ee1eSDan Willemsen	fdValue := fds.ByNumber(genid.Any_Value_field_number)
349*1c12ee1eSDan Willemsen	value := any.Get(fdValue)
350*1c12ee1eSDan Willemsen	err = proto.UnmarshalOptions{
351*1c12ee1eSDan Willemsen		AllowPartial: true,
352*1c12ee1eSDan Willemsen		Resolver:     e.opts.Resolver,
353*1c12ee1eSDan Willemsen	}.Unmarshal(value.Bytes(), m)
354*1c12ee1eSDan Willemsen	if err != nil {
355*1c12ee1eSDan Willemsen		return false
356*1c12ee1eSDan Willemsen	}
357*1c12ee1eSDan Willemsen
358*1c12ee1eSDan Willemsen	// Get current encoder position. If marshaling fails, reset encoder output
359*1c12ee1eSDan Willemsen	// back to this position.
360*1c12ee1eSDan Willemsen	pos := e.Snapshot()
361*1c12ee1eSDan Willemsen
362*1c12ee1eSDan Willemsen	// Field name is the proto field name enclosed in [].
363*1c12ee1eSDan Willemsen	e.WriteName("[" + typeURL + "]")
364*1c12ee1eSDan Willemsen	err = e.marshalMessage(m.ProtoReflect(), true)
365*1c12ee1eSDan Willemsen	if err != nil {
366*1c12ee1eSDan Willemsen		e.Reset(pos)
367*1c12ee1eSDan Willemsen		return false
368*1c12ee1eSDan Willemsen	}
369*1c12ee1eSDan Willemsen	return true
370*1c12ee1eSDan Willemsen}
371