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