encode.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // 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. package text
  5. import (
  6. "bytes"
  7. "math/rand"
  8. "strings"
  9. "github.com/golang/protobuf/v2/internal/errors"
  10. )
  11. // Marshal serializes v as the proto text format, where v must be a Message.
  12. // In the proto text format, the top-level value is always a message where the
  13. // delimiters are elided.
  14. //
  15. // If indent is a non-empty string, it causes every entry in a List or Message
  16. // to be preceded by the indent and trailed by a newline.
  17. //
  18. // If delims is not the zero value, it controls the delimiter characters used
  19. // for messages (e.g., "{}" vs "<>").
  20. //
  21. // If outputASCII is true, strings will be serialized in such a way that
  22. // multi-byte UTF-8 sequences are escaped. This property ensures that the
  23. // overall output is ASCII (as opposed to UTF-8).
  24. func Marshal(v Value, indent string, delims [2]byte, outputASCII bool) ([]byte, error) {
  25. p := encoder{}
  26. if len(indent) > 0 {
  27. if strings.Trim(indent, " \t") != "" {
  28. return nil, errors.New("indent may only be composed of space and tab characters")
  29. }
  30. p.indent = indent
  31. p.newline = "\n"
  32. }
  33. switch delims {
  34. case [2]byte{0, 0}:
  35. p.delims = [2]byte{'{', '}'}
  36. case [2]byte{'{', '}'}, [2]byte{'<', '>'}:
  37. p.delims = delims
  38. default:
  39. return nil, errors.New("delimiters may only be \"{}\" or \"<>\"")
  40. }
  41. p.outputASCII = outputASCII
  42. err := p.marshalMessage(v, false)
  43. if !p.nerr.Merge(err) {
  44. return nil, err
  45. }
  46. if len(indent) > 0 {
  47. return append(bytes.TrimRight(p.out, "\n"), '\n'), p.nerr.E
  48. }
  49. return p.out, p.nerr.E
  50. }
  51. type encoder struct {
  52. nerr errors.NonFatal
  53. out []byte
  54. indent string
  55. indents []byte
  56. newline string // set to "\n" if len(indent) > 0
  57. delims [2]byte
  58. outputASCII bool
  59. }
  60. func (p *encoder) marshalList(v Value) error {
  61. if v.Type() != List {
  62. return errors.New("invalid type %v, expected list", v.Type())
  63. }
  64. elems := v.List()
  65. p.out = append(p.out, '[')
  66. p.indents = append(p.indents, p.indent...)
  67. if len(elems) > 0 {
  68. p.out = append(p.out, p.newline...)
  69. }
  70. for i, elem := range elems {
  71. p.out = append(p.out, p.indents...)
  72. if err := p.marshalValue(elem); !p.nerr.Merge(err) {
  73. return err
  74. }
  75. if i < len(elems)-1 {
  76. p.out = append(p.out, ',')
  77. }
  78. p.out = append(p.out, p.newline...)
  79. }
  80. p.indents = p.indents[:len(p.indents)-len(p.indent)]
  81. if len(elems) > 0 {
  82. p.out = append(p.out, p.indents...)
  83. }
  84. p.out = append(p.out, ']')
  85. return nil
  86. }
  87. func (p *encoder) marshalMessage(v Value, emitDelims bool) error {
  88. if v.Type() != Message {
  89. return errors.New("invalid type %v, expected message", v.Type())
  90. }
  91. items := v.Message()
  92. if emitDelims {
  93. p.out = append(p.out, p.delims[0])
  94. p.indents = append(p.indents, p.indent...)
  95. if len(items) > 0 {
  96. p.out = append(p.out, p.newline...)
  97. }
  98. }
  99. spaceAdded := false
  100. for i, item := range items {
  101. p.out = append(p.out, p.indents...)
  102. if err := p.marshalKey(item[0]); !p.nerr.Merge(err) {
  103. return err
  104. }
  105. p.out = append(p.out, ':')
  106. if len(p.indent) > 0 {
  107. p.out = append(p.out, ' ')
  108. }
  109. // For multi-line output, add a random extra space after key: per message to
  110. // make output unstable.
  111. if !spaceAdded && len(p.indent) > 0 && rand.Intn(2) == 1 {
  112. p.out = append(p.out, ' ')
  113. spaceAdded = true
  114. }
  115. if err := p.marshalValue(item[1]); !p.nerr.Merge(err) {
  116. return err
  117. }
  118. if i < len(items)-1 && len(p.indent) == 0 {
  119. p.out = append(p.out, ' ')
  120. }
  121. // For single-line output, add a random extra space after a field per message to
  122. // make output unstable.
  123. if !spaceAdded && len(p.indent) == 0 && i != len(items)-1 && rand.Intn(2) == 1 {
  124. p.out = append(p.out, ' ')
  125. spaceAdded = true
  126. }
  127. p.out = append(p.out, p.newline...)
  128. }
  129. if emitDelims {
  130. p.indents = p.indents[:len(p.indents)-len(p.indent)]
  131. if len(items) > 0 {
  132. p.out = append(p.out, p.indents...)
  133. }
  134. p.out = append(p.out, p.delims[1])
  135. }
  136. return nil
  137. }
  138. func (p *encoder) marshalKey(v Value) error {
  139. switch v.Type() {
  140. case String:
  141. var err error
  142. p.out = append(p.out, '[')
  143. if len(urlRegexp.FindString(v.str)) == len(v.str) {
  144. p.out = append(p.out, v.str...)
  145. } else {
  146. err = p.marshalString(v)
  147. }
  148. p.out = append(p.out, ']')
  149. return err
  150. case Uint:
  151. return p.marshalNumber(v)
  152. case Name:
  153. s, _ := v.Name()
  154. p.out = append(p.out, s...)
  155. return nil
  156. default:
  157. return errors.New("invalid type %v to encode key", v.Type())
  158. }
  159. }
  160. func (p *encoder) marshalValue(v Value) error {
  161. switch v.Type() {
  162. case Bool, Int, Uint, Float:
  163. return p.marshalNumber(v)
  164. case String:
  165. return p.marshalString(v)
  166. case List:
  167. return p.marshalList(v)
  168. case Message:
  169. return p.marshalMessage(v, true)
  170. case Name:
  171. s, _ := v.Name()
  172. p.out = append(p.out, s...)
  173. return nil
  174. default:
  175. return errors.New("invalid type %v to encode value", v.Type())
  176. }
  177. }