xref: /aosp_15_r20/external/golang-protobuf/testing/protopack/pack.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 Willemsen// Package protopack enables manual encoding and decoding of protobuf wire data.
6*1c12ee1eSDan Willemsen//
7*1c12ee1eSDan Willemsen// This package is intended for use in debugging and/or creation of test data.
8*1c12ee1eSDan Willemsen// Proper usage of this package requires knowledge of the wire format.
9*1c12ee1eSDan Willemsen//
10*1c12ee1eSDan Willemsen// See https://protobuf.dev/programming-guides/encoding.
11*1c12ee1eSDan Willemsenpackage protopack
12*1c12ee1eSDan Willemsen
13*1c12ee1eSDan Willemsenimport (
14*1c12ee1eSDan Willemsen	"fmt"
15*1c12ee1eSDan Willemsen	"io"
16*1c12ee1eSDan Willemsen	"math"
17*1c12ee1eSDan Willemsen	"path"
18*1c12ee1eSDan Willemsen	"reflect"
19*1c12ee1eSDan Willemsen	"strconv"
20*1c12ee1eSDan Willemsen	"strings"
21*1c12ee1eSDan Willemsen	"unicode"
22*1c12ee1eSDan Willemsen	"unicode/utf8"
23*1c12ee1eSDan Willemsen
24*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/encoding/protowire"
25*1c12ee1eSDan Willemsen	"google.golang.org/protobuf/reflect/protoreflect"
26*1c12ee1eSDan Willemsen)
27*1c12ee1eSDan Willemsen
28*1c12ee1eSDan Willemsen// Number is the field number; aliased from the protowire package for convenience.
29*1c12ee1eSDan Willemsentype Number = protowire.Number
30*1c12ee1eSDan Willemsen
31*1c12ee1eSDan Willemsen// Number type constants; copied from the protowire package for convenience.
32*1c12ee1eSDan Willemsenconst (
33*1c12ee1eSDan Willemsen	MinValidNumber      Number = protowire.MinValidNumber
34*1c12ee1eSDan Willemsen	FirstReservedNumber Number = protowire.FirstReservedNumber
35*1c12ee1eSDan Willemsen	LastReservedNumber  Number = protowire.LastReservedNumber
36*1c12ee1eSDan Willemsen	MaxValidNumber      Number = protowire.MaxValidNumber
37*1c12ee1eSDan Willemsen)
38*1c12ee1eSDan Willemsen
39*1c12ee1eSDan Willemsen// Type is the wire type; aliased from the protowire package for convenience.
40*1c12ee1eSDan Willemsentype Type = protowire.Type
41*1c12ee1eSDan Willemsen
42*1c12ee1eSDan Willemsen// Wire type constants; copied from the protowire package for convenience.
43*1c12ee1eSDan Willemsenconst (
44*1c12ee1eSDan Willemsen	VarintType     Type = protowire.VarintType
45*1c12ee1eSDan Willemsen	Fixed32Type    Type = protowire.Fixed32Type
46*1c12ee1eSDan Willemsen	Fixed64Type    Type = protowire.Fixed64Type
47*1c12ee1eSDan Willemsen	BytesType      Type = protowire.BytesType
48*1c12ee1eSDan Willemsen	StartGroupType Type = protowire.StartGroupType
49*1c12ee1eSDan Willemsen	EndGroupType   Type = protowire.EndGroupType
50*1c12ee1eSDan Willemsen)
51*1c12ee1eSDan Willemsen
52*1c12ee1eSDan Willemsentype (
53*1c12ee1eSDan Willemsen	// Token is any other type (e.g., Message, Tag, Varint, Float32, etc).
54*1c12ee1eSDan Willemsen	Token token
55*1c12ee1eSDan Willemsen	// Message is an ordered sequence of  Tokens, where certain tokens may
56*1c12ee1eSDan Willemsen	// contain other tokens. It is functionally a concrete syntax tree that
57*1c12ee1eSDan Willemsen	// losslessly represents any arbitrary wire data (including invalid input).
58*1c12ee1eSDan Willemsen	Message []Token
59*1c12ee1eSDan Willemsen
60*1c12ee1eSDan Willemsen	// Tag is a tuple of the field number and the wire type.
61*1c12ee1eSDan Willemsen	Tag struct {
62*1c12ee1eSDan Willemsen		Number Number
63*1c12ee1eSDan Willemsen		Type   Type
64*1c12ee1eSDan Willemsen	}
65*1c12ee1eSDan Willemsen	// Bool is a boolean.
66*1c12ee1eSDan Willemsen	Bool bool
67*1c12ee1eSDan Willemsen	// Varint is a signed varint using 64-bit two's complement encoding.
68*1c12ee1eSDan Willemsen	Varint int64
69*1c12ee1eSDan Willemsen	// Svarint is a signed varint using zig-zag encoding.
70*1c12ee1eSDan Willemsen	Svarint int64
71*1c12ee1eSDan Willemsen	// Uvarint is a unsigned varint.
72*1c12ee1eSDan Willemsen	Uvarint uint64
73*1c12ee1eSDan Willemsen
74*1c12ee1eSDan Willemsen	// Int32 is a signed 32-bit fixed-width integer.
75*1c12ee1eSDan Willemsen	Int32 int32
76*1c12ee1eSDan Willemsen	// Uint32 is an unsigned 32-bit fixed-width integer.
77*1c12ee1eSDan Willemsen	Uint32 uint32
78*1c12ee1eSDan Willemsen	// Float32 is a 32-bit fixed-width floating point number.
79*1c12ee1eSDan Willemsen	Float32 float32
80*1c12ee1eSDan Willemsen
81*1c12ee1eSDan Willemsen	// Int64 is a signed 64-bit fixed-width integer.
82*1c12ee1eSDan Willemsen	Int64 int64
83*1c12ee1eSDan Willemsen	// Uint64 is an unsigned 64-bit fixed-width integer.
84*1c12ee1eSDan Willemsen	Uint64 uint64
85*1c12ee1eSDan Willemsen	// Float64 is a 64-bit fixed-width floating point number.
86*1c12ee1eSDan Willemsen	Float64 float64
87*1c12ee1eSDan Willemsen
88*1c12ee1eSDan Willemsen	// String is a length-prefixed string.
89*1c12ee1eSDan Willemsen	String string
90*1c12ee1eSDan Willemsen	// Bytes is a length-prefixed bytes.
91*1c12ee1eSDan Willemsen	Bytes []byte
92*1c12ee1eSDan Willemsen	// LengthPrefix is a length-prefixed message.
93*1c12ee1eSDan Willemsen	LengthPrefix Message
94*1c12ee1eSDan Willemsen
95*1c12ee1eSDan Willemsen	// Denormalized is a denormalized varint value, where a varint is encoded
96*1c12ee1eSDan Willemsen	// using more bytes than is strictly necessary. The number of extra bytes
97*1c12ee1eSDan Willemsen	// alone is sufficient to losslessly represent the denormalized varint.
98*1c12ee1eSDan Willemsen	//
99*1c12ee1eSDan Willemsen	// The value may be one of Tag, Bool, Varint, Svarint, or Uvarint,
100*1c12ee1eSDan Willemsen	// where the varint representation of each token is denormalized.
101*1c12ee1eSDan Willemsen	//
102*1c12ee1eSDan Willemsen	// Alternatively, the value may be one of String, Bytes, or LengthPrefix,
103*1c12ee1eSDan Willemsen	// where the varint representation of the length-prefix is denormalized.
104*1c12ee1eSDan Willemsen	Denormalized struct {
105*1c12ee1eSDan Willemsen		Count uint // number of extra bytes
106*1c12ee1eSDan Willemsen		Value Token
107*1c12ee1eSDan Willemsen	}
108*1c12ee1eSDan Willemsen
109*1c12ee1eSDan Willemsen	// Raw are bytes directly appended to output.
110*1c12ee1eSDan Willemsen	Raw []byte
111*1c12ee1eSDan Willemsen)
112*1c12ee1eSDan Willemsen
113*1c12ee1eSDan Willemsentype token interface {
114*1c12ee1eSDan Willemsen	isToken()
115*1c12ee1eSDan Willemsen}
116*1c12ee1eSDan Willemsen
117*1c12ee1eSDan Willemsenfunc (Message) isToken()      {}
118*1c12ee1eSDan Willemsenfunc (Tag) isToken()          {}
119*1c12ee1eSDan Willemsenfunc (Bool) isToken()         {}
120*1c12ee1eSDan Willemsenfunc (Varint) isToken()       {}
121*1c12ee1eSDan Willemsenfunc (Svarint) isToken()      {}
122*1c12ee1eSDan Willemsenfunc (Uvarint) isToken()      {}
123*1c12ee1eSDan Willemsenfunc (Int32) isToken()        {}
124*1c12ee1eSDan Willemsenfunc (Uint32) isToken()       {}
125*1c12ee1eSDan Willemsenfunc (Float32) isToken()      {}
126*1c12ee1eSDan Willemsenfunc (Int64) isToken()        {}
127*1c12ee1eSDan Willemsenfunc (Uint64) isToken()       {}
128*1c12ee1eSDan Willemsenfunc (Float64) isToken()      {}
129*1c12ee1eSDan Willemsenfunc (String) isToken()       {}
130*1c12ee1eSDan Willemsenfunc (Bytes) isToken()        {}
131*1c12ee1eSDan Willemsenfunc (LengthPrefix) isToken() {}
132*1c12ee1eSDan Willemsenfunc (Denormalized) isToken() {}
133*1c12ee1eSDan Willemsenfunc (Raw) isToken()          {}
134*1c12ee1eSDan Willemsen
135*1c12ee1eSDan Willemsen// Size reports the size in bytes of the marshaled message.
136*1c12ee1eSDan Willemsenfunc (m Message) Size() int {
137*1c12ee1eSDan Willemsen	var n int
138*1c12ee1eSDan Willemsen	for _, v := range m {
139*1c12ee1eSDan Willemsen		switch v := v.(type) {
140*1c12ee1eSDan Willemsen		case Message:
141*1c12ee1eSDan Willemsen			n += v.Size()
142*1c12ee1eSDan Willemsen		case Tag:
143*1c12ee1eSDan Willemsen			n += protowire.SizeTag(v.Number)
144*1c12ee1eSDan Willemsen		case Bool:
145*1c12ee1eSDan Willemsen			n += protowire.SizeVarint(protowire.EncodeBool(false))
146*1c12ee1eSDan Willemsen		case Varint:
147*1c12ee1eSDan Willemsen			n += protowire.SizeVarint(uint64(v))
148*1c12ee1eSDan Willemsen		case Svarint:
149*1c12ee1eSDan Willemsen			n += protowire.SizeVarint(protowire.EncodeZigZag(int64(v)))
150*1c12ee1eSDan Willemsen		case Uvarint:
151*1c12ee1eSDan Willemsen			n += protowire.SizeVarint(uint64(v))
152*1c12ee1eSDan Willemsen		case Int32, Uint32, Float32:
153*1c12ee1eSDan Willemsen			n += protowire.SizeFixed32()
154*1c12ee1eSDan Willemsen		case Int64, Uint64, Float64:
155*1c12ee1eSDan Willemsen			n += protowire.SizeFixed64()
156*1c12ee1eSDan Willemsen		case String:
157*1c12ee1eSDan Willemsen			n += protowire.SizeBytes(len(v))
158*1c12ee1eSDan Willemsen		case Bytes:
159*1c12ee1eSDan Willemsen			n += protowire.SizeBytes(len(v))
160*1c12ee1eSDan Willemsen		case LengthPrefix:
161*1c12ee1eSDan Willemsen			n += protowire.SizeBytes(Message(v).Size())
162*1c12ee1eSDan Willemsen		case Denormalized:
163*1c12ee1eSDan Willemsen			n += int(v.Count) + Message{v.Value}.Size()
164*1c12ee1eSDan Willemsen		case Raw:
165*1c12ee1eSDan Willemsen			n += len(v)
166*1c12ee1eSDan Willemsen		default:
167*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("unknown type: %T", v))
168*1c12ee1eSDan Willemsen		}
169*1c12ee1eSDan Willemsen	}
170*1c12ee1eSDan Willemsen	return n
171*1c12ee1eSDan Willemsen}
172*1c12ee1eSDan Willemsen
173*1c12ee1eSDan Willemsen// Marshal encodes a syntax tree into the protobuf wire format.
174*1c12ee1eSDan Willemsen//
175*1c12ee1eSDan Willemsen// Example message definition:
176*1c12ee1eSDan Willemsen//
177*1c12ee1eSDan Willemsen//	message MyMessage {
178*1c12ee1eSDan Willemsen//		string field1 = 1;
179*1c12ee1eSDan Willemsen//		int64 field2 = 2;
180*1c12ee1eSDan Willemsen//		repeated float32 field3 = 3;
181*1c12ee1eSDan Willemsen//	}
182*1c12ee1eSDan Willemsen//
183*1c12ee1eSDan Willemsen// Example encoded message:
184*1c12ee1eSDan Willemsen//
185*1c12ee1eSDan Willemsen//	b := Message{
186*1c12ee1eSDan Willemsen//		Tag{1, BytesType}, String("Hello, world!"),
187*1c12ee1eSDan Willemsen//		Tag{2, VarintType}, Varint(-10),
188*1c12ee1eSDan Willemsen//		Tag{3, BytesType}, LengthPrefix{
189*1c12ee1eSDan Willemsen//			Float32(1.1), Float32(2.2), Float32(3.3),
190*1c12ee1eSDan Willemsen//		},
191*1c12ee1eSDan Willemsen//	}.Marshal()
192*1c12ee1eSDan Willemsen//
193*1c12ee1eSDan Willemsen// Resulting wire data:
194*1c12ee1eSDan Willemsen//
195*1c12ee1eSDan Willemsen//	0x0000  0a 0d 48 65 6c 6c 6f 2c  20 77 6f 72 6c 64 21 10  |..Hello, world!.|
196*1c12ee1eSDan Willemsen//	0x0010  f6 ff ff ff ff ff ff ff  ff 01 1a 0c cd cc 8c 3f  |...............?|
197*1c12ee1eSDan Willemsen//	0x0020  cd cc 0c 40 33 33 53 40                           |...@33S@|
198*1c12ee1eSDan Willemsenfunc (m Message) Marshal() []byte {
199*1c12ee1eSDan Willemsen	var out []byte
200*1c12ee1eSDan Willemsen	for _, v := range m {
201*1c12ee1eSDan Willemsen		switch v := v.(type) {
202*1c12ee1eSDan Willemsen		case Message:
203*1c12ee1eSDan Willemsen			out = append(out, v.Marshal()...)
204*1c12ee1eSDan Willemsen		case Tag:
205*1c12ee1eSDan Willemsen			out = protowire.AppendTag(out, v.Number, v.Type)
206*1c12ee1eSDan Willemsen		case Bool:
207*1c12ee1eSDan Willemsen			out = protowire.AppendVarint(out, protowire.EncodeBool(bool(v)))
208*1c12ee1eSDan Willemsen		case Varint:
209*1c12ee1eSDan Willemsen			out = protowire.AppendVarint(out, uint64(v))
210*1c12ee1eSDan Willemsen		case Svarint:
211*1c12ee1eSDan Willemsen			out = protowire.AppendVarint(out, protowire.EncodeZigZag(int64(v)))
212*1c12ee1eSDan Willemsen		case Uvarint:
213*1c12ee1eSDan Willemsen			out = protowire.AppendVarint(out, uint64(v))
214*1c12ee1eSDan Willemsen		case Int32:
215*1c12ee1eSDan Willemsen			out = protowire.AppendFixed32(out, uint32(v))
216*1c12ee1eSDan Willemsen		case Uint32:
217*1c12ee1eSDan Willemsen			out = protowire.AppendFixed32(out, uint32(v))
218*1c12ee1eSDan Willemsen		case Float32:
219*1c12ee1eSDan Willemsen			out = protowire.AppendFixed32(out, math.Float32bits(float32(v)))
220*1c12ee1eSDan Willemsen		case Int64:
221*1c12ee1eSDan Willemsen			out = protowire.AppendFixed64(out, uint64(v))
222*1c12ee1eSDan Willemsen		case Uint64:
223*1c12ee1eSDan Willemsen			out = protowire.AppendFixed64(out, uint64(v))
224*1c12ee1eSDan Willemsen		case Float64:
225*1c12ee1eSDan Willemsen			out = protowire.AppendFixed64(out, math.Float64bits(float64(v)))
226*1c12ee1eSDan Willemsen		case String:
227*1c12ee1eSDan Willemsen			out = protowire.AppendBytes(out, []byte(v))
228*1c12ee1eSDan Willemsen		case Bytes:
229*1c12ee1eSDan Willemsen			out = protowire.AppendBytes(out, []byte(v))
230*1c12ee1eSDan Willemsen		case LengthPrefix:
231*1c12ee1eSDan Willemsen			out = protowire.AppendBytes(out, Message(v).Marshal())
232*1c12ee1eSDan Willemsen		case Denormalized:
233*1c12ee1eSDan Willemsen			b := Message{v.Value}.Marshal()
234*1c12ee1eSDan Willemsen			_, n := protowire.ConsumeVarint(b)
235*1c12ee1eSDan Willemsen			out = append(out, b[:n]...)
236*1c12ee1eSDan Willemsen			for i := uint(0); i < v.Count; i++ {
237*1c12ee1eSDan Willemsen				out[len(out)-1] |= 0x80 // set continuation bit on previous
238*1c12ee1eSDan Willemsen				out = append(out, 0)
239*1c12ee1eSDan Willemsen			}
240*1c12ee1eSDan Willemsen			out = append(out, b[n:]...)
241*1c12ee1eSDan Willemsen		case Raw:
242*1c12ee1eSDan Willemsen			return append(out, v...)
243*1c12ee1eSDan Willemsen		default:
244*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("unknown type: %T", v))
245*1c12ee1eSDan Willemsen		}
246*1c12ee1eSDan Willemsen	}
247*1c12ee1eSDan Willemsen	return out
248*1c12ee1eSDan Willemsen}
249*1c12ee1eSDan Willemsen
250*1c12ee1eSDan Willemsen// Unmarshal parses the input protobuf wire data as a syntax tree.
251*1c12ee1eSDan Willemsen// Any parsing error results in the remainder of the input being
252*1c12ee1eSDan Willemsen// concatenated to the message as a Raw type.
253*1c12ee1eSDan Willemsen//
254*1c12ee1eSDan Willemsen// Each tag (a tuple of the field number and wire type) encountered is
255*1c12ee1eSDan Willemsen// inserted into the syntax tree as a Tag.
256*1c12ee1eSDan Willemsen//
257*1c12ee1eSDan Willemsen// The contents of each wire type is mapped to the following Go types:
258*1c12ee1eSDan Willemsen//
259*1c12ee1eSDan Willemsen//	VarintType   => Uvarint
260*1c12ee1eSDan Willemsen//	Fixed32Type  => Uint32
261*1c12ee1eSDan Willemsen//	Fixed64Type  => Uint64
262*1c12ee1eSDan Willemsen//	BytesType    => Bytes
263*1c12ee1eSDan Willemsen//	GroupType    => Message
264*1c12ee1eSDan Willemsen//
265*1c12ee1eSDan Willemsen// Since the wire format is not self-describing, this function cannot parse
266*1c12ee1eSDan Willemsen// sub-messages and will leave them as the Bytes type. Further manual parsing
267*1c12ee1eSDan Willemsen// can be performed as such:
268*1c12ee1eSDan Willemsen//
269*1c12ee1eSDan Willemsen//	var m, m1, m2 Message
270*1c12ee1eSDan Willemsen//	m.Unmarshal(b)
271*1c12ee1eSDan Willemsen//	m1.Unmarshal(m[3].(Bytes))
272*1c12ee1eSDan Willemsen//	m[3] = LengthPrefix(m1)
273*1c12ee1eSDan Willemsen//	m2.Unmarshal(m[3].(LengthPrefix)[1].(Bytes))
274*1c12ee1eSDan Willemsen//	m[3].(LengthPrefix)[1] = LengthPrefix(m2)
275*1c12ee1eSDan Willemsen//
276*1c12ee1eSDan Willemsen// Unmarshal is useful for debugging the protobuf wire format.
277*1c12ee1eSDan Willemsenfunc (m *Message) Unmarshal(in []byte) {
278*1c12ee1eSDan Willemsen	m.unmarshal(in, nil, false)
279*1c12ee1eSDan Willemsen}
280*1c12ee1eSDan Willemsen
281*1c12ee1eSDan Willemsen// UnmarshalDescriptor parses the input protobuf wire data as a syntax tree
282*1c12ee1eSDan Willemsen// using the provided message descriptor for more accurate parsing of fields.
283*1c12ee1eSDan Willemsen// It operates like Unmarshal, but may use a wider range of Go types to
284*1c12ee1eSDan Willemsen// represent the wire data.
285*1c12ee1eSDan Willemsen//
286*1c12ee1eSDan Willemsen// The contents of each wire type is mapped to one of the following Go types:
287*1c12ee1eSDan Willemsen//
288*1c12ee1eSDan Willemsen//	VarintType   => Bool, Varint, Svarint, Uvarint
289*1c12ee1eSDan Willemsen//	Fixed32Type  => Int32, Uint32, Float32
290*1c12ee1eSDan Willemsen//	Fixed64Type  => Uint32, Uint64, Float64
291*1c12ee1eSDan Willemsen//	BytesType    => String, Bytes, LengthPrefix
292*1c12ee1eSDan Willemsen//	GroupType    => Message
293*1c12ee1eSDan Willemsen//
294*1c12ee1eSDan Willemsen// If the field is unknown, it uses the same mapping as Unmarshal.
295*1c12ee1eSDan Willemsen// Known sub-messages are parsed as a Message and packed repeated fields are
296*1c12ee1eSDan Willemsen// parsed as a LengthPrefix.
297*1c12ee1eSDan Willemsenfunc (m *Message) UnmarshalDescriptor(in []byte, desc protoreflect.MessageDescriptor) {
298*1c12ee1eSDan Willemsen	m.unmarshal(in, desc, false)
299*1c12ee1eSDan Willemsen}
300*1c12ee1eSDan Willemsen
301*1c12ee1eSDan Willemsen// UnmarshalAbductive is like UnmarshalDescriptor, but infers abductively
302*1c12ee1eSDan Willemsen// whether any unknown bytes values is a message based on whether it is
303*1c12ee1eSDan Willemsen// a syntactically well-formed message.
304*1c12ee1eSDan Willemsen//
305*1c12ee1eSDan Willemsen// Note that the protobuf wire format is not fully self-describing,
306*1c12ee1eSDan Willemsen// so abductive inference may attempt to expand a bytes value as a message
307*1c12ee1eSDan Willemsen// that is not actually a message. It is a best-effort guess.
308*1c12ee1eSDan Willemsenfunc (m *Message) UnmarshalAbductive(in []byte, desc protoreflect.MessageDescriptor) {
309*1c12ee1eSDan Willemsen	m.unmarshal(in, desc, true)
310*1c12ee1eSDan Willemsen}
311*1c12ee1eSDan Willemsen
312*1c12ee1eSDan Willemsenfunc (m *Message) unmarshal(in []byte, desc protoreflect.MessageDescriptor, inferMessage bool) {
313*1c12ee1eSDan Willemsen	p := parser{in: in, out: *m}
314*1c12ee1eSDan Willemsen	p.parseMessage(desc, false, inferMessage)
315*1c12ee1eSDan Willemsen	*m = p.out
316*1c12ee1eSDan Willemsen}
317*1c12ee1eSDan Willemsen
318*1c12ee1eSDan Willemsentype parser struct {
319*1c12ee1eSDan Willemsen	in  []byte
320*1c12ee1eSDan Willemsen	out []Token
321*1c12ee1eSDan Willemsen
322*1c12ee1eSDan Willemsen	invalid bool
323*1c12ee1eSDan Willemsen}
324*1c12ee1eSDan Willemsen
325*1c12ee1eSDan Willemsenfunc (p *parser) parseMessage(msgDesc protoreflect.MessageDescriptor, group, inferMessage bool) {
326*1c12ee1eSDan Willemsen	for len(p.in) > 0 {
327*1c12ee1eSDan Willemsen		v, n := protowire.ConsumeVarint(p.in)
328*1c12ee1eSDan Willemsen		num, typ := protowire.DecodeTag(v)
329*1c12ee1eSDan Willemsen		if n < 0 || num <= 0 || v > math.MaxUint32 {
330*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Raw(p.in)), nil
331*1c12ee1eSDan Willemsen			p.invalid = true
332*1c12ee1eSDan Willemsen			return
333*1c12ee1eSDan Willemsen		}
334*1c12ee1eSDan Willemsen		if typ == EndGroupType && group {
335*1c12ee1eSDan Willemsen			return // if inside a group, then stop
336*1c12ee1eSDan Willemsen		}
337*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Tag{num, typ}), p.in[n:]
338*1c12ee1eSDan Willemsen		if m := n - protowire.SizeVarint(v); m > 0 {
339*1c12ee1eSDan Willemsen			p.out[len(p.out)-1] = Denormalized{uint(m), p.out[len(p.out)-1]}
340*1c12ee1eSDan Willemsen		}
341*1c12ee1eSDan Willemsen
342*1c12ee1eSDan Willemsen		// If descriptor is available, use it for more accurate parsing.
343*1c12ee1eSDan Willemsen		var isPacked bool
344*1c12ee1eSDan Willemsen		var kind protoreflect.Kind
345*1c12ee1eSDan Willemsen		var subDesc protoreflect.MessageDescriptor
346*1c12ee1eSDan Willemsen		if msgDesc != nil && !msgDesc.IsPlaceholder() {
347*1c12ee1eSDan Willemsen			if fieldDesc := msgDesc.Fields().ByNumber(num); fieldDesc != nil {
348*1c12ee1eSDan Willemsen				isPacked = fieldDesc.IsPacked()
349*1c12ee1eSDan Willemsen				kind = fieldDesc.Kind()
350*1c12ee1eSDan Willemsen				switch kind {
351*1c12ee1eSDan Willemsen				case protoreflect.MessageKind, protoreflect.GroupKind:
352*1c12ee1eSDan Willemsen					subDesc = fieldDesc.Message()
353*1c12ee1eSDan Willemsen					if subDesc == nil || subDesc.IsPlaceholder() {
354*1c12ee1eSDan Willemsen						kind = 0
355*1c12ee1eSDan Willemsen					}
356*1c12ee1eSDan Willemsen				}
357*1c12ee1eSDan Willemsen			}
358*1c12ee1eSDan Willemsen		}
359*1c12ee1eSDan Willemsen
360*1c12ee1eSDan Willemsen		switch typ {
361*1c12ee1eSDan Willemsen		case VarintType:
362*1c12ee1eSDan Willemsen			p.parseVarint(kind)
363*1c12ee1eSDan Willemsen		case Fixed32Type:
364*1c12ee1eSDan Willemsen			p.parseFixed32(kind)
365*1c12ee1eSDan Willemsen		case Fixed64Type:
366*1c12ee1eSDan Willemsen			p.parseFixed64(kind)
367*1c12ee1eSDan Willemsen		case BytesType:
368*1c12ee1eSDan Willemsen			p.parseBytes(isPacked, kind, subDesc, inferMessage)
369*1c12ee1eSDan Willemsen		case StartGroupType:
370*1c12ee1eSDan Willemsen			p.parseGroup(num, subDesc, inferMessage)
371*1c12ee1eSDan Willemsen		case EndGroupType:
372*1c12ee1eSDan Willemsen			// Handled by p.parseGroup.
373*1c12ee1eSDan Willemsen		default:
374*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Raw(p.in)), nil
375*1c12ee1eSDan Willemsen			p.invalid = true
376*1c12ee1eSDan Willemsen		}
377*1c12ee1eSDan Willemsen	}
378*1c12ee1eSDan Willemsen}
379*1c12ee1eSDan Willemsen
380*1c12ee1eSDan Willemsenfunc (p *parser) parseVarint(kind protoreflect.Kind) {
381*1c12ee1eSDan Willemsen	v, n := protowire.ConsumeVarint(p.in)
382*1c12ee1eSDan Willemsen	if n < 0 {
383*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Raw(p.in)), nil
384*1c12ee1eSDan Willemsen		p.invalid = true
385*1c12ee1eSDan Willemsen		return
386*1c12ee1eSDan Willemsen	}
387*1c12ee1eSDan Willemsen	switch kind {
388*1c12ee1eSDan Willemsen	case protoreflect.BoolKind:
389*1c12ee1eSDan Willemsen		switch v {
390*1c12ee1eSDan Willemsen		case 0:
391*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Bool(false)), p.in[n:]
392*1c12ee1eSDan Willemsen		case 1:
393*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Bool(true)), p.in[n:]
394*1c12ee1eSDan Willemsen		default:
395*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Uvarint(v)), p.in[n:]
396*1c12ee1eSDan Willemsen		}
397*1c12ee1eSDan Willemsen	case protoreflect.Int32Kind, protoreflect.Int64Kind:
398*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Varint(v)), p.in[n:]
399*1c12ee1eSDan Willemsen	case protoreflect.Sint32Kind, protoreflect.Sint64Kind:
400*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Svarint(protowire.DecodeZigZag(v))), p.in[n:]
401*1c12ee1eSDan Willemsen	default:
402*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Uvarint(v)), p.in[n:]
403*1c12ee1eSDan Willemsen	}
404*1c12ee1eSDan Willemsen	if m := n - protowire.SizeVarint(v); m > 0 {
405*1c12ee1eSDan Willemsen		p.out[len(p.out)-1] = Denormalized{uint(m), p.out[len(p.out)-1]}
406*1c12ee1eSDan Willemsen	}
407*1c12ee1eSDan Willemsen}
408*1c12ee1eSDan Willemsen
409*1c12ee1eSDan Willemsenfunc (p *parser) parseFixed32(kind protoreflect.Kind) {
410*1c12ee1eSDan Willemsen	v, n := protowire.ConsumeFixed32(p.in)
411*1c12ee1eSDan Willemsen	if n < 0 {
412*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Raw(p.in)), nil
413*1c12ee1eSDan Willemsen		p.invalid = true
414*1c12ee1eSDan Willemsen		return
415*1c12ee1eSDan Willemsen	}
416*1c12ee1eSDan Willemsen	switch kind {
417*1c12ee1eSDan Willemsen	case protoreflect.FloatKind:
418*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Float32(math.Float32frombits(v))), p.in[n:]
419*1c12ee1eSDan Willemsen	case protoreflect.Sfixed32Kind:
420*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Int32(v)), p.in[n:]
421*1c12ee1eSDan Willemsen	default:
422*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Uint32(v)), p.in[n:]
423*1c12ee1eSDan Willemsen	}
424*1c12ee1eSDan Willemsen}
425*1c12ee1eSDan Willemsen
426*1c12ee1eSDan Willemsenfunc (p *parser) parseFixed64(kind protoreflect.Kind) {
427*1c12ee1eSDan Willemsen	v, n := protowire.ConsumeFixed64(p.in)
428*1c12ee1eSDan Willemsen	if n < 0 {
429*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Raw(p.in)), nil
430*1c12ee1eSDan Willemsen		p.invalid = true
431*1c12ee1eSDan Willemsen		return
432*1c12ee1eSDan Willemsen	}
433*1c12ee1eSDan Willemsen	switch kind {
434*1c12ee1eSDan Willemsen	case protoreflect.DoubleKind:
435*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Float64(math.Float64frombits(v))), p.in[n:]
436*1c12ee1eSDan Willemsen	case protoreflect.Sfixed64Kind:
437*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Int64(v)), p.in[n:]
438*1c12ee1eSDan Willemsen	default:
439*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Uint64(v)), p.in[n:]
440*1c12ee1eSDan Willemsen	}
441*1c12ee1eSDan Willemsen}
442*1c12ee1eSDan Willemsen
443*1c12ee1eSDan Willemsenfunc (p *parser) parseBytes(isPacked bool, kind protoreflect.Kind, desc protoreflect.MessageDescriptor, inferMessage bool) {
444*1c12ee1eSDan Willemsen	v, n := protowire.ConsumeVarint(p.in)
445*1c12ee1eSDan Willemsen	if n < 0 {
446*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Raw(p.in)), nil
447*1c12ee1eSDan Willemsen		p.invalid = true
448*1c12ee1eSDan Willemsen		return
449*1c12ee1eSDan Willemsen	}
450*1c12ee1eSDan Willemsen	p.out, p.in = append(p.out, Uvarint(v)), p.in[n:]
451*1c12ee1eSDan Willemsen	if m := n - protowire.SizeVarint(v); m > 0 {
452*1c12ee1eSDan Willemsen		p.out[len(p.out)-1] = Denormalized{uint(m), p.out[len(p.out)-1]}
453*1c12ee1eSDan Willemsen	}
454*1c12ee1eSDan Willemsen	if v > uint64(len(p.in)) {
455*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Raw(p.in)), nil
456*1c12ee1eSDan Willemsen		p.invalid = true
457*1c12ee1eSDan Willemsen		return
458*1c12ee1eSDan Willemsen	}
459*1c12ee1eSDan Willemsen	p.out = p.out[:len(p.out)-1] // subsequent tokens contain prefix-length
460*1c12ee1eSDan Willemsen
461*1c12ee1eSDan Willemsen	if isPacked {
462*1c12ee1eSDan Willemsen		p.parsePacked(int(v), kind)
463*1c12ee1eSDan Willemsen	} else {
464*1c12ee1eSDan Willemsen		switch kind {
465*1c12ee1eSDan Willemsen		case protoreflect.MessageKind:
466*1c12ee1eSDan Willemsen			p2 := parser{in: p.in[:v]}
467*1c12ee1eSDan Willemsen			p2.parseMessage(desc, false, inferMessage)
468*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, LengthPrefix(p2.out)), p.in[v:]
469*1c12ee1eSDan Willemsen		case protoreflect.StringKind:
470*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, String(p.in[:v])), p.in[v:]
471*1c12ee1eSDan Willemsen		case protoreflect.BytesKind:
472*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Bytes(p.in[:v])), p.in[v:]
473*1c12ee1eSDan Willemsen		default:
474*1c12ee1eSDan Willemsen			if inferMessage {
475*1c12ee1eSDan Willemsen				// Check whether this is a syntactically valid message.
476*1c12ee1eSDan Willemsen				p2 := parser{in: p.in[:v]}
477*1c12ee1eSDan Willemsen				p2.parseMessage(nil, false, inferMessage)
478*1c12ee1eSDan Willemsen				if !p2.invalid {
479*1c12ee1eSDan Willemsen					p.out, p.in = append(p.out, LengthPrefix(p2.out)), p.in[v:]
480*1c12ee1eSDan Willemsen					break
481*1c12ee1eSDan Willemsen				}
482*1c12ee1eSDan Willemsen			}
483*1c12ee1eSDan Willemsen			p.out, p.in = append(p.out, Bytes(p.in[:v])), p.in[v:]
484*1c12ee1eSDan Willemsen		}
485*1c12ee1eSDan Willemsen	}
486*1c12ee1eSDan Willemsen	if m := n - protowire.SizeVarint(v); m > 0 {
487*1c12ee1eSDan Willemsen		p.out[len(p.out)-1] = Denormalized{uint(m), p.out[len(p.out)-1]}
488*1c12ee1eSDan Willemsen	}
489*1c12ee1eSDan Willemsen}
490*1c12ee1eSDan Willemsen
491*1c12ee1eSDan Willemsenfunc (p *parser) parsePacked(n int, kind protoreflect.Kind) {
492*1c12ee1eSDan Willemsen	p2 := parser{in: p.in[:n]}
493*1c12ee1eSDan Willemsen	for len(p2.in) > 0 {
494*1c12ee1eSDan Willemsen		switch kind {
495*1c12ee1eSDan Willemsen		case protoreflect.BoolKind, protoreflect.EnumKind,
496*1c12ee1eSDan Willemsen			protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind,
497*1c12ee1eSDan Willemsen			protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind:
498*1c12ee1eSDan Willemsen			p2.parseVarint(kind)
499*1c12ee1eSDan Willemsen		case protoreflect.Fixed32Kind, protoreflect.Sfixed32Kind, protoreflect.FloatKind:
500*1c12ee1eSDan Willemsen			p2.parseFixed32(kind)
501*1c12ee1eSDan Willemsen		case protoreflect.Fixed64Kind, protoreflect.Sfixed64Kind, protoreflect.DoubleKind:
502*1c12ee1eSDan Willemsen			p2.parseFixed64(kind)
503*1c12ee1eSDan Willemsen		default:
504*1c12ee1eSDan Willemsen			panic(fmt.Sprintf("invalid packed kind: %v", kind))
505*1c12ee1eSDan Willemsen		}
506*1c12ee1eSDan Willemsen	}
507*1c12ee1eSDan Willemsen	p.out, p.in = append(p.out, LengthPrefix(p2.out)), p.in[n:]
508*1c12ee1eSDan Willemsen}
509*1c12ee1eSDan Willemsen
510*1c12ee1eSDan Willemsenfunc (p *parser) parseGroup(startNum protowire.Number, desc protoreflect.MessageDescriptor, inferMessage bool) {
511*1c12ee1eSDan Willemsen	p2 := parser{in: p.in}
512*1c12ee1eSDan Willemsen	p2.parseMessage(desc, true, inferMessage)
513*1c12ee1eSDan Willemsen	if len(p2.out) > 0 {
514*1c12ee1eSDan Willemsen		p.out = append(p.out, Message(p2.out))
515*1c12ee1eSDan Willemsen	}
516*1c12ee1eSDan Willemsen	p.in = p2.in
517*1c12ee1eSDan Willemsen
518*1c12ee1eSDan Willemsen	// Append the trailing end group.
519*1c12ee1eSDan Willemsen	v, n := protowire.ConsumeVarint(p.in)
520*1c12ee1eSDan Willemsen	if endNum, typ := protowire.DecodeTag(v); typ == EndGroupType {
521*1c12ee1eSDan Willemsen		if startNum != endNum {
522*1c12ee1eSDan Willemsen			p.invalid = true
523*1c12ee1eSDan Willemsen		}
524*1c12ee1eSDan Willemsen		p.out, p.in = append(p.out, Tag{endNum, typ}), p.in[n:]
525*1c12ee1eSDan Willemsen		if m := n - protowire.SizeVarint(v); m > 0 {
526*1c12ee1eSDan Willemsen			p.out[len(p.out)-1] = Denormalized{uint(m), p.out[len(p.out)-1]}
527*1c12ee1eSDan Willemsen		}
528*1c12ee1eSDan Willemsen	}
529*1c12ee1eSDan Willemsen}
530*1c12ee1eSDan Willemsen
531*1c12ee1eSDan Willemsen// Format implements a custom formatter to visualize the syntax tree.
532*1c12ee1eSDan Willemsen// Using "%#v" formats the Message in Go source code.
533*1c12ee1eSDan Willemsenfunc (m Message) Format(s fmt.State, r rune) {
534*1c12ee1eSDan Willemsen	switch r {
535*1c12ee1eSDan Willemsen	case 'x':
536*1c12ee1eSDan Willemsen		io.WriteString(s, fmt.Sprintf("%x", m.Marshal()))
537*1c12ee1eSDan Willemsen	case 'X':
538*1c12ee1eSDan Willemsen		io.WriteString(s, fmt.Sprintf("%X", m.Marshal()))
539*1c12ee1eSDan Willemsen	case 'v':
540*1c12ee1eSDan Willemsen		switch {
541*1c12ee1eSDan Willemsen		case s.Flag('#'):
542*1c12ee1eSDan Willemsen			io.WriteString(s, m.format(true, true))
543*1c12ee1eSDan Willemsen		case s.Flag('+'):
544*1c12ee1eSDan Willemsen			io.WriteString(s, m.format(false, true))
545*1c12ee1eSDan Willemsen		default:
546*1c12ee1eSDan Willemsen			io.WriteString(s, m.format(false, false))
547*1c12ee1eSDan Willemsen		}
548*1c12ee1eSDan Willemsen	default:
549*1c12ee1eSDan Willemsen		panic("invalid verb: " + string(r))
550*1c12ee1eSDan Willemsen	}
551*1c12ee1eSDan Willemsen}
552*1c12ee1eSDan Willemsen
553*1c12ee1eSDan Willemsen// format formats the message.
554*1c12ee1eSDan Willemsen// If source is enabled, this emits valid Go source.
555*1c12ee1eSDan Willemsen// If multi is enabled, the output may span multiple lines.
556*1c12ee1eSDan Willemsenfunc (m Message) format(source, multi bool) string {
557*1c12ee1eSDan Willemsen	var ss []string
558*1c12ee1eSDan Willemsen	var prefix, nextPrefix string
559*1c12ee1eSDan Willemsen	for _, v := range m {
560*1c12ee1eSDan Willemsen		// Ensure certain tokens have preceding or succeeding newlines.
561*1c12ee1eSDan Willemsen		prefix, nextPrefix = nextPrefix, " "
562*1c12ee1eSDan Willemsen		if multi {
563*1c12ee1eSDan Willemsen			switch v := v.(type) {
564*1c12ee1eSDan Willemsen			case Tag: // only has preceding newline
565*1c12ee1eSDan Willemsen				prefix = "\n"
566*1c12ee1eSDan Willemsen			case Denormalized: // only has preceding newline
567*1c12ee1eSDan Willemsen				if _, ok := v.Value.(Tag); ok {
568*1c12ee1eSDan Willemsen					prefix = "\n"
569*1c12ee1eSDan Willemsen				}
570*1c12ee1eSDan Willemsen			case Message, Raw: // has preceding and succeeding newlines
571*1c12ee1eSDan Willemsen				prefix, nextPrefix = "\n", "\n"
572*1c12ee1eSDan Willemsen			}
573*1c12ee1eSDan Willemsen		}
574*1c12ee1eSDan Willemsen
575*1c12ee1eSDan Willemsen		s := formatToken(v, source, multi)
576*1c12ee1eSDan Willemsen		ss = append(ss, prefix+s+",")
577*1c12ee1eSDan Willemsen	}
578*1c12ee1eSDan Willemsen
579*1c12ee1eSDan Willemsen	var s string
580*1c12ee1eSDan Willemsen	if len(ss) > 0 {
581*1c12ee1eSDan Willemsen		s = strings.TrimSpace(strings.Join(ss, ""))
582*1c12ee1eSDan Willemsen		if multi {
583*1c12ee1eSDan Willemsen			s = "\n\t" + strings.Join(strings.Split(s, "\n"), "\n\t") + "\n"
584*1c12ee1eSDan Willemsen		} else {
585*1c12ee1eSDan Willemsen			s = strings.TrimSuffix(s, ",")
586*1c12ee1eSDan Willemsen		}
587*1c12ee1eSDan Willemsen	}
588*1c12ee1eSDan Willemsen	s = fmt.Sprintf("%T{%s}", m, s)
589*1c12ee1eSDan Willemsen	if !source {
590*1c12ee1eSDan Willemsen		s = trimPackage(s)
591*1c12ee1eSDan Willemsen	}
592*1c12ee1eSDan Willemsen	return s
593*1c12ee1eSDan Willemsen}
594*1c12ee1eSDan Willemsen
595*1c12ee1eSDan Willemsen// formatToken formats a single token.
596*1c12ee1eSDan Willemsenfunc formatToken(t Token, source, multi bool) (s string) {
597*1c12ee1eSDan Willemsen	switch v := t.(type) {
598*1c12ee1eSDan Willemsen	case Message:
599*1c12ee1eSDan Willemsen		s = v.format(source, multi)
600*1c12ee1eSDan Willemsen	case LengthPrefix:
601*1c12ee1eSDan Willemsen		s = formatPacked(v, source, multi)
602*1c12ee1eSDan Willemsen		if s == "" {
603*1c12ee1eSDan Willemsen			ms := Message(v).format(source, multi)
604*1c12ee1eSDan Willemsen			s = fmt.Sprintf("%T(%s)", v, ms)
605*1c12ee1eSDan Willemsen		}
606*1c12ee1eSDan Willemsen	case Tag:
607*1c12ee1eSDan Willemsen		s = fmt.Sprintf("%T{%d, %s}", v, v.Number, formatType(v.Type, source))
608*1c12ee1eSDan Willemsen	case Bool, Varint, Svarint, Uvarint, Int32, Uint32, Float32, Int64, Uint64, Float64:
609*1c12ee1eSDan Willemsen		if source {
610*1c12ee1eSDan Willemsen			// Print floats in a way that preserves exact precision.
611*1c12ee1eSDan Willemsen			if f, _ := v.(Float32); math.IsNaN(float64(f)) || math.IsInf(float64(f), 0) {
612*1c12ee1eSDan Willemsen				switch {
613*1c12ee1eSDan Willemsen				case f > 0:
614*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.Inf(+1))", v)
615*1c12ee1eSDan Willemsen				case f < 0:
616*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.Inf(-1))", v)
617*1c12ee1eSDan Willemsen				case math.Float32bits(float32(math.NaN())) == math.Float32bits(float32(f)):
618*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.NaN())", v)
619*1c12ee1eSDan Willemsen				default:
620*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.Float32frombits(0x%08x))", v, math.Float32bits(float32(f)))
621*1c12ee1eSDan Willemsen				}
622*1c12ee1eSDan Willemsen				break
623*1c12ee1eSDan Willemsen			}
624*1c12ee1eSDan Willemsen			if f, _ := v.(Float64); math.IsNaN(float64(f)) || math.IsInf(float64(f), 0) {
625*1c12ee1eSDan Willemsen				switch {
626*1c12ee1eSDan Willemsen				case f > 0:
627*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.Inf(+1))", v)
628*1c12ee1eSDan Willemsen				case f < 0:
629*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.Inf(-1))", v)
630*1c12ee1eSDan Willemsen				case math.Float64bits(float64(math.NaN())) == math.Float64bits(float64(f)):
631*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.NaN())", v)
632*1c12ee1eSDan Willemsen				default:
633*1c12ee1eSDan Willemsen					s = fmt.Sprintf("%T(math.Float64frombits(0x%016x))", v, math.Float64bits(float64(f)))
634*1c12ee1eSDan Willemsen				}
635*1c12ee1eSDan Willemsen				break
636*1c12ee1eSDan Willemsen			}
637*1c12ee1eSDan Willemsen		}
638*1c12ee1eSDan Willemsen		s = fmt.Sprintf("%T(%v)", v, v)
639*1c12ee1eSDan Willemsen	case String, Bytes, Raw:
640*1c12ee1eSDan Willemsen		s = fmt.Sprintf("%s", v)
641*1c12ee1eSDan Willemsen		s = fmt.Sprintf("%T(%s)", v, formatString(s))
642*1c12ee1eSDan Willemsen	case Denormalized:
643*1c12ee1eSDan Willemsen		s = fmt.Sprintf("%T{+%d, %v}", v, v.Count, formatToken(v.Value, source, multi))
644*1c12ee1eSDan Willemsen	default:
645*1c12ee1eSDan Willemsen		panic(fmt.Sprintf("unknown type: %T", v))
646*1c12ee1eSDan Willemsen	}
647*1c12ee1eSDan Willemsen	if !source {
648*1c12ee1eSDan Willemsen		s = trimPackage(s)
649*1c12ee1eSDan Willemsen	}
650*1c12ee1eSDan Willemsen	return s
651*1c12ee1eSDan Willemsen}
652*1c12ee1eSDan Willemsen
653*1c12ee1eSDan Willemsen// formatPacked returns a non-empty string if LengthPrefix looks like a packed
654*1c12ee1eSDan Willemsen// repeated field of primitives.
655*1c12ee1eSDan Willemsenfunc formatPacked(v LengthPrefix, source, multi bool) string {
656*1c12ee1eSDan Willemsen	var ss []string
657*1c12ee1eSDan Willemsen	for _, v := range v {
658*1c12ee1eSDan Willemsen		switch v.(type) {
659*1c12ee1eSDan Willemsen		case Bool, Varint, Svarint, Uvarint, Int32, Uint32, Float32, Int64, Uint64, Float64, Denormalized, Raw:
660*1c12ee1eSDan Willemsen			if v, ok := v.(Denormalized); ok {
661*1c12ee1eSDan Willemsen				switch v.Value.(type) {
662*1c12ee1eSDan Willemsen				case Bool, Varint, Svarint, Uvarint:
663*1c12ee1eSDan Willemsen				default:
664*1c12ee1eSDan Willemsen					return ""
665*1c12ee1eSDan Willemsen				}
666*1c12ee1eSDan Willemsen			}
667*1c12ee1eSDan Willemsen			ss = append(ss, formatToken(v, source, multi))
668*1c12ee1eSDan Willemsen		default:
669*1c12ee1eSDan Willemsen			return ""
670*1c12ee1eSDan Willemsen		}
671*1c12ee1eSDan Willemsen	}
672*1c12ee1eSDan Willemsen	s := fmt.Sprintf("%T{%s}", v, strings.Join(ss, ", "))
673*1c12ee1eSDan Willemsen	if !source {
674*1c12ee1eSDan Willemsen		s = trimPackage(s)
675*1c12ee1eSDan Willemsen	}
676*1c12ee1eSDan Willemsen	return s
677*1c12ee1eSDan Willemsen}
678*1c12ee1eSDan Willemsen
679*1c12ee1eSDan Willemsen// formatType returns the name for Type.
680*1c12ee1eSDan Willemsenfunc formatType(t Type, source bool) (s string) {
681*1c12ee1eSDan Willemsen	switch t {
682*1c12ee1eSDan Willemsen	case VarintType:
683*1c12ee1eSDan Willemsen		s = pkg + ".VarintType"
684*1c12ee1eSDan Willemsen	case Fixed32Type:
685*1c12ee1eSDan Willemsen		s = pkg + ".Fixed32Type"
686*1c12ee1eSDan Willemsen	case Fixed64Type:
687*1c12ee1eSDan Willemsen		s = pkg + ".Fixed64Type"
688*1c12ee1eSDan Willemsen	case BytesType:
689*1c12ee1eSDan Willemsen		s = pkg + ".BytesType"
690*1c12ee1eSDan Willemsen	case StartGroupType:
691*1c12ee1eSDan Willemsen		s = pkg + ".StartGroupType"
692*1c12ee1eSDan Willemsen	case EndGroupType:
693*1c12ee1eSDan Willemsen		s = pkg + ".EndGroupType"
694*1c12ee1eSDan Willemsen	default:
695*1c12ee1eSDan Willemsen		s = fmt.Sprintf("Type(%d)", t)
696*1c12ee1eSDan Willemsen	}
697*1c12ee1eSDan Willemsen	if !source {
698*1c12ee1eSDan Willemsen		s = strings.TrimSuffix(trimPackage(s), "Type")
699*1c12ee1eSDan Willemsen	}
700*1c12ee1eSDan Willemsen	return s
701*1c12ee1eSDan Willemsen}
702*1c12ee1eSDan Willemsen
703*1c12ee1eSDan Willemsen// formatString returns a quoted string for s.
704*1c12ee1eSDan Willemsenfunc formatString(s string) string {
705*1c12ee1eSDan Willemsen	// Use quoted string if it the same length as a raw string literal.
706*1c12ee1eSDan Willemsen	// Otherwise, attempt to use the raw string form.
707*1c12ee1eSDan Willemsen	qs := strconv.Quote(s)
708*1c12ee1eSDan Willemsen	if len(qs) == 1+len(s)+1 {
709*1c12ee1eSDan Willemsen		return qs
710*1c12ee1eSDan Willemsen	}
711*1c12ee1eSDan Willemsen
712*1c12ee1eSDan Willemsen	// Disallow newlines to ensure output is a single line.
713*1c12ee1eSDan Willemsen	// Disallow non-printable runes for readability purposes.
714*1c12ee1eSDan Willemsen	rawInvalid := func(r rune) bool {
715*1c12ee1eSDan Willemsen		return r == '`' || r == '\n' || r == utf8.RuneError || !unicode.IsPrint(r)
716*1c12ee1eSDan Willemsen	}
717*1c12ee1eSDan Willemsen	if strings.IndexFunc(s, rawInvalid) < 0 {
718*1c12ee1eSDan Willemsen		return "`" + s + "`"
719*1c12ee1eSDan Willemsen	}
720*1c12ee1eSDan Willemsen	return qs
721*1c12ee1eSDan Willemsen}
722*1c12ee1eSDan Willemsen
723*1c12ee1eSDan Willemsenvar pkg = path.Base(reflect.TypeOf(Tag{}).PkgPath())
724*1c12ee1eSDan Willemsen
725*1c12ee1eSDan Willemsenfunc trimPackage(s string) string {
726*1c12ee1eSDan Willemsen	return strings.TrimPrefix(strings.TrimPrefix(s, pkg), ".")
727*1c12ee1eSDan Willemsen}
728