text.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2019 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. package proto
  5. // Functions for writing the text protocol buffer format.
  6. import (
  7. "bytes"
  8. "encoding"
  9. "io"
  10. "reflect"
  11. "google.golang.org/protobuf/encoding/prototext"
  12. preg "google.golang.org/protobuf/reflect/protoregistry"
  13. "google.golang.org/protobuf/runtime/protoimpl"
  14. )
  15. // TextMarshaler is a configurable text format marshaler.
  16. type TextMarshaler struct {
  17. Compact bool // use compact text format in one line without the trailing newline character
  18. ExpandAny bool // expand google.protobuf.Any messages of known types
  19. }
  20. // Marshal writes a given protocol buffer in text format.
  21. func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
  22. val := reflect.ValueOf(pb)
  23. // V1 supports passing in nil interface or pointer and outputs <nil>, while
  24. // V2 will panic on nil interface and outputs nothing for nil pointer.
  25. if pb == nil || val.IsNil() {
  26. w.Write([]byte("<nil>"))
  27. return nil
  28. }
  29. // V1-specific override in marshaling.
  30. if etm, ok := pb.(encoding.TextMarshaler); ok {
  31. text, err := etm.MarshalText()
  32. if err != nil {
  33. return err
  34. }
  35. if _, err = w.Write(text); err != nil {
  36. return err
  37. }
  38. return nil
  39. }
  40. var ind string
  41. if !tm.Compact {
  42. ind = " "
  43. }
  44. mo := prototext.MarshalOptions{
  45. AllowPartial: true,
  46. Indent: ind,
  47. }
  48. if !tm.ExpandAny {
  49. mo.Resolver = emptyResolver
  50. }
  51. b, err := mo.Marshal(protoimpl.X.MessageOf(pb).Interface())
  52. mask := nonFatalErrors(err)
  53. // V1 does not return invalid UTF-8 error.
  54. if err != nil && mask&errInvalidUTF8 == 0 {
  55. return err
  56. }
  57. if _, err := w.Write(b); err != nil {
  58. return err
  59. }
  60. return nil
  61. }
  62. // Text is the same as Marshal, but returns the string directly.
  63. func (tm *TextMarshaler) Text(pb Message) string {
  64. var buf bytes.Buffer
  65. tm.Marshal(&buf, pb)
  66. return buf.String()
  67. }
  68. var (
  69. emptyResolver = preg.NewTypes()
  70. defaultTextMarshaler = TextMarshaler{}
  71. compactTextMarshaler = TextMarshaler{Compact: true}
  72. )
  73. // MarshalText writes a given protocol buffer in text format.
  74. func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
  75. // MarshalTextString is the same as MarshalText, but returns the string directly.
  76. func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
  77. // CompactText writes a given protocol buffer in compact text format (one line).
  78. func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
  79. // CompactTextString is the same as CompactText, but returns the string directly.
  80. func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
  81. // UnmarshalText reads a protocol buffer in text format. UnmarshalText resets pb
  82. // before starting to unmarshal, so any existing data in pb is always removed.
  83. // If a required field is not set and no other error occurs, UnmarshalText
  84. // returns *RequiredNotSetError.
  85. func UnmarshalText(s string, m Message) error {
  86. if um, ok := m.(encoding.TextUnmarshaler); ok {
  87. return um.UnmarshalText([]byte(s))
  88. }
  89. err := prototext.Unmarshal([]byte(s), protoimpl.X.MessageOf(m).Interface())
  90. // Return RequiredNotSetError for required not set errors and ignore invalid
  91. // UTF-8 errors.
  92. mask := nonFatalErrors(err)
  93. if mask&errRequiredNotSet > 0 {
  94. return &RequiredNotSetError{}
  95. }
  96. if mask&errInvalidUTF8 > 0 {
  97. return nil
  98. }
  99. // Otherwise return error which can either be nil or fatal.
  100. return err
  101. }