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