format.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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 msgfmt implements a text marshaler combining the desirable features
  5. // of both the JSON and proto text formats.
  6. // It is optimized for human readability and has no associated deserializer.
  7. package msgfmt
  8. import (
  9. "bytes"
  10. "fmt"
  11. "reflect"
  12. "sort"
  13. "strconv"
  14. "strings"
  15. "time"
  16. "google.golang.org/protobuf/encoding/protowire"
  17. "google.golang.org/protobuf/internal/detrand"
  18. "google.golang.org/protobuf/internal/genid"
  19. "google.golang.org/protobuf/internal/order"
  20. "google.golang.org/protobuf/proto"
  21. "google.golang.org/protobuf/reflect/protoreflect"
  22. "google.golang.org/protobuf/reflect/protoregistry"
  23. )
  24. // Format returns a formatted string for the message.
  25. func Format(m proto.Message) string {
  26. return string(appendMessage(nil, m.ProtoReflect()))
  27. }
  28. // FormatValue returns a formatted string for an arbitrary value.
  29. func FormatValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) string {
  30. return string(appendValue(nil, v, fd))
  31. }
  32. func appendValue(b []byte, v protoreflect.Value, fd protoreflect.FieldDescriptor) []byte {
  33. switch v := v.Interface().(type) {
  34. case nil:
  35. return append(b, "<invalid>"...)
  36. case bool, int32, int64, uint32, uint64, float32, float64:
  37. return append(b, fmt.Sprint(v)...)
  38. case string:
  39. return append(b, strconv.Quote(string(v))...)
  40. case []byte:
  41. return append(b, strconv.Quote(string(v))...)
  42. case protoreflect.EnumNumber:
  43. return appendEnum(b, v, fd)
  44. case protoreflect.Message:
  45. return appendMessage(b, v)
  46. case protoreflect.List:
  47. return appendList(b, v, fd)
  48. case protoreflect.Map:
  49. return appendMap(b, v, fd)
  50. default:
  51. panic(fmt.Sprintf("invalid type: %T", v))
  52. }
  53. }
  54. func appendEnum(b []byte, v protoreflect.EnumNumber, fd protoreflect.FieldDescriptor) []byte {
  55. if fd != nil {
  56. if ev := fd.Enum().Values().ByNumber(v); ev != nil {
  57. return append(b, ev.Name()...)
  58. }
  59. }
  60. return strconv.AppendInt(b, int64(v), 10)
  61. }
  62. func appendMessage(b []byte, m protoreflect.Message) []byte {
  63. if b2 := appendKnownMessage(b, m); b2 != nil {
  64. return b2
  65. }
  66. b = append(b, '{')
  67. order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
  68. b = append(b, fd.TextName()...)
  69. b = append(b, ':')
  70. b = appendValue(b, v, fd)
  71. b = append(b, delim()...)
  72. return true
  73. })
  74. b = appendUnknown(b, m.GetUnknown())
  75. b = bytes.TrimRight(b, delim())
  76. b = append(b, '}')
  77. return b
  78. }
  79. var protocmpMessageType = reflect.TypeOf(map[string]any(nil))
  80. func appendKnownMessage(b []byte, m protoreflect.Message) []byte {
  81. md := m.Descriptor()
  82. fds := md.Fields()
  83. switch md.FullName() {
  84. case genid.Any_message_fullname:
  85. var msgVal protoreflect.Message
  86. url := m.Get(fds.ByNumber(genid.Any_TypeUrl_field_number)).String()
  87. if v := reflect.ValueOf(m); v.Type().ConvertibleTo(protocmpMessageType) {
  88. // For protocmp.Message, directly obtain the sub-message value
  89. // which is stored in structured form, rather than as raw bytes.
  90. m2 := v.Convert(protocmpMessageType).Interface().(map[string]any)
  91. v, ok := m2[string(genid.Any_Value_field_name)].(proto.Message)
  92. if !ok {
  93. return nil
  94. }
  95. msgVal = v.ProtoReflect()
  96. } else {
  97. val := m.Get(fds.ByNumber(genid.Any_Value_field_number)).Bytes()
  98. mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
  99. if err != nil {
  100. return nil
  101. }
  102. msgVal = mt.New()
  103. err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(val, msgVal.Interface())
  104. if err != nil {
  105. return nil
  106. }
  107. }
  108. b = append(b, '{')
  109. b = append(b, "["+url+"]"...)
  110. b = append(b, ':')
  111. b = appendMessage(b, msgVal)
  112. b = append(b, '}')
  113. return b
  114. case genid.Timestamp_message_fullname:
  115. secs := m.Get(fds.ByNumber(genid.Timestamp_Seconds_field_number)).Int()
  116. nanos := m.Get(fds.ByNumber(genid.Timestamp_Nanos_field_number)).Int()
  117. if nanos < 0 || nanos >= 1e9 {
  118. return nil
  119. }
  120. t := time.Unix(secs, nanos).UTC()
  121. x := t.Format("2006-01-02T15:04:05.000000000") // RFC 3339
  122. x = strings.TrimSuffix(x, "000")
  123. x = strings.TrimSuffix(x, "000")
  124. x = strings.TrimSuffix(x, ".000")
  125. return append(b, x+"Z"...)
  126. case genid.Duration_message_fullname:
  127. sign := ""
  128. secs := m.Get(fds.ByNumber(genid.Duration_Seconds_field_number)).Int()
  129. nanos := m.Get(fds.ByNumber(genid.Duration_Nanos_field_number)).Int()
  130. if nanos <= -1e9 || nanos >= 1e9 || (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) {
  131. return nil
  132. }
  133. if secs < 0 || nanos < 0 {
  134. sign, secs, nanos = "-", -1*secs, -1*nanos
  135. }
  136. x := fmt.Sprintf("%s%d.%09d", sign, secs, nanos)
  137. x = strings.TrimSuffix(x, "000")
  138. x = strings.TrimSuffix(x, "000")
  139. x = strings.TrimSuffix(x, ".000")
  140. return append(b, x+"s"...)
  141. case genid.BoolValue_message_fullname,
  142. genid.Int32Value_message_fullname,
  143. genid.Int64Value_message_fullname,
  144. genid.UInt32Value_message_fullname,
  145. genid.UInt64Value_message_fullname,
  146. genid.FloatValue_message_fullname,
  147. genid.DoubleValue_message_fullname,
  148. genid.StringValue_message_fullname,
  149. genid.BytesValue_message_fullname:
  150. fd := fds.ByNumber(genid.WrapperValue_Value_field_number)
  151. return appendValue(b, m.Get(fd), fd)
  152. }
  153. return nil
  154. }
  155. func appendUnknown(b []byte, raw protoreflect.RawFields) []byte {
  156. rs := make(map[protoreflect.FieldNumber][]protoreflect.RawFields)
  157. for len(raw) > 0 {
  158. num, _, n := protowire.ConsumeField(raw)
  159. rs[num] = append(rs[num], raw[:n])
  160. raw = raw[n:]
  161. }
  162. var ns []protoreflect.FieldNumber
  163. for n := range rs {
  164. ns = append(ns, n)
  165. }
  166. sort.Slice(ns, func(i, j int) bool { return ns[i] < ns[j] })
  167. for _, n := range ns {
  168. var leftBracket, rightBracket string
  169. if len(rs[n]) > 1 {
  170. leftBracket, rightBracket = "[", "]"
  171. }
  172. b = strconv.AppendInt(b, int64(n), 10)
  173. b = append(b, ':')
  174. b = append(b, leftBracket...)
  175. for _, r := range rs[n] {
  176. num, typ, n := protowire.ConsumeTag(r)
  177. r = r[n:]
  178. switch typ {
  179. case protowire.VarintType:
  180. v, _ := protowire.ConsumeVarint(r)
  181. b = strconv.AppendInt(b, int64(v), 10)
  182. case protowire.Fixed32Type:
  183. v, _ := protowire.ConsumeFixed32(r)
  184. b = append(b, fmt.Sprintf("0x%08x", v)...)
  185. case protowire.Fixed64Type:
  186. v, _ := protowire.ConsumeFixed64(r)
  187. b = append(b, fmt.Sprintf("0x%016x", v)...)
  188. case protowire.BytesType:
  189. v, _ := protowire.ConsumeBytes(r)
  190. b = strconv.AppendQuote(b, string(v))
  191. case protowire.StartGroupType:
  192. v, _ := protowire.ConsumeGroup(num, r)
  193. b = append(b, '{')
  194. b = appendUnknown(b, v)
  195. b = bytes.TrimRight(b, delim())
  196. b = append(b, '}')
  197. default:
  198. panic(fmt.Sprintf("invalid type: %v", typ))
  199. }
  200. b = append(b, delim()...)
  201. }
  202. b = bytes.TrimRight(b, delim())
  203. b = append(b, rightBracket...)
  204. b = append(b, delim()...)
  205. }
  206. return b
  207. }
  208. func appendList(b []byte, v protoreflect.List, fd protoreflect.FieldDescriptor) []byte {
  209. b = append(b, '[')
  210. for i := 0; i < v.Len(); i++ {
  211. b = appendValue(b, v.Get(i), fd)
  212. b = append(b, delim()...)
  213. }
  214. b = bytes.TrimRight(b, delim())
  215. b = append(b, ']')
  216. return b
  217. }
  218. func appendMap(b []byte, v protoreflect.Map, fd protoreflect.FieldDescriptor) []byte {
  219. b = append(b, '{')
  220. order.RangeEntries(v, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
  221. b = appendValue(b, k.Value(), fd.MapKey())
  222. b = append(b, ':')
  223. b = appendValue(b, v, fd.MapValue())
  224. b = append(b, delim()...)
  225. return true
  226. })
  227. b = bytes.TrimRight(b, delim())
  228. b = append(b, '}')
  229. return b
  230. }
  231. func delim() string {
  232. // Deliberately introduce instability into the message string to
  233. // discourage users from depending on it.
  234. if detrand.Bool() {
  235. return " "
  236. }
  237. return ", "
  238. }