step.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // Copyright 2020 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 protopath
  5. import (
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "google.golang.org/protobuf/internal/encoding/text"
  10. "google.golang.org/protobuf/reflect/protoreflect"
  11. )
  12. // StepKind identifies the kind of step operation.
  13. // Each kind of step corresponds with some protobuf reflection operation.
  14. type StepKind int
  15. const (
  16. invalidStep StepKind = iota
  17. // RootStep identifies a step as the Root step operation.
  18. RootStep
  19. // FieldAccessStep identifies a step as the FieldAccess step operation.
  20. FieldAccessStep
  21. // UnknownAccessStep identifies a step as the UnknownAccess step operation.
  22. UnknownAccessStep
  23. // ListIndexStep identifies a step as the ListIndex step operation.
  24. ListIndexStep
  25. // MapIndexStep identifies a step as the MapIndex step operation.
  26. MapIndexStep
  27. // AnyExpandStep identifies a step as the AnyExpand step operation.
  28. AnyExpandStep
  29. )
  30. func (k StepKind) String() string {
  31. switch k {
  32. case invalidStep:
  33. return "<invalid>"
  34. case RootStep:
  35. return "Root"
  36. case FieldAccessStep:
  37. return "FieldAccess"
  38. case UnknownAccessStep:
  39. return "UnknownAccess"
  40. case ListIndexStep:
  41. return "ListIndex"
  42. case MapIndexStep:
  43. return "MapIndex"
  44. case AnyExpandStep:
  45. return "AnyExpand"
  46. default:
  47. return fmt.Sprintf("<unknown:%d>", k)
  48. }
  49. }
  50. // Step is a union where only one step operation may be specified at a time.
  51. // The different kinds of steps are specified by the constants defined for
  52. // the StepKind type.
  53. type Step struct {
  54. kind StepKind
  55. desc protoreflect.Descriptor
  56. key protoreflect.Value
  57. }
  58. // Root indicates the root message that a path is relative to.
  59. // It should always (and only ever) be the first step in a path.
  60. func Root(md protoreflect.MessageDescriptor) Step {
  61. if md == nil {
  62. panic("nil message descriptor")
  63. }
  64. return Step{kind: RootStep, desc: md}
  65. }
  66. // FieldAccess describes access of a field within a message.
  67. // Extension field accesses are also represented using a FieldAccess and
  68. // must be provided with a protoreflect.FieldDescriptor
  69. //
  70. // Within the context of Values,
  71. // the type of the previous step value is always a message, and
  72. // the type of the current step value is determined by the field descriptor.
  73. func FieldAccess(fd protoreflect.FieldDescriptor) Step {
  74. if fd == nil {
  75. panic("nil field descriptor")
  76. } else if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok && fd.IsExtension() {
  77. panic(fmt.Sprintf("extension field %q must implement protoreflect.ExtensionTypeDescriptor", fd.FullName()))
  78. }
  79. return Step{kind: FieldAccessStep, desc: fd}
  80. }
  81. // UnknownAccess describes access to the unknown fields within a message.
  82. //
  83. // Within the context of Values,
  84. // the type of the previous step value is always a message, and
  85. // the type of the current step value is always a bytes type.
  86. func UnknownAccess() Step {
  87. return Step{kind: UnknownAccessStep}
  88. }
  89. // ListIndex describes index of an element within a list.
  90. //
  91. // Within the context of Values,
  92. // the type of the previous, previous step value is always a message,
  93. // the type of the previous step value is always a list, and
  94. // the type of the current step value is determined by the field descriptor.
  95. func ListIndex(i int) Step {
  96. if i < 0 {
  97. panic(fmt.Sprintf("invalid list index: %v", i))
  98. }
  99. return Step{kind: ListIndexStep, key: protoreflect.ValueOfInt64(int64(i))}
  100. }
  101. // MapIndex describes index of an entry within a map.
  102. // The key type is determined by field descriptor that the map belongs to.
  103. //
  104. // Within the context of Values,
  105. // the type of the previous previous step value is always a message,
  106. // the type of the previous step value is always a map, and
  107. // the type of the current step value is determined by the field descriptor.
  108. func MapIndex(k protoreflect.MapKey) Step {
  109. if !k.IsValid() {
  110. panic("invalid map index")
  111. }
  112. return Step{kind: MapIndexStep, key: k.Value()}
  113. }
  114. // AnyExpand describes expansion of a google.protobuf.Any message into
  115. // a structured representation of the underlying message.
  116. //
  117. // Within the context of Values,
  118. // the type of the previous step value is always a google.protobuf.Any message, and
  119. // the type of the current step value is always a message.
  120. func AnyExpand(md protoreflect.MessageDescriptor) Step {
  121. if md == nil {
  122. panic("nil message descriptor")
  123. }
  124. return Step{kind: AnyExpandStep, desc: md}
  125. }
  126. // MessageDescriptor returns the message descriptor for Root or AnyExpand steps,
  127. // otherwise it returns nil.
  128. func (s Step) MessageDescriptor() protoreflect.MessageDescriptor {
  129. switch s.kind {
  130. case RootStep, AnyExpandStep:
  131. return s.desc.(protoreflect.MessageDescriptor)
  132. default:
  133. return nil
  134. }
  135. }
  136. // FieldDescriptor returns the field descriptor for FieldAccess steps,
  137. // otherwise it returns nil.
  138. func (s Step) FieldDescriptor() protoreflect.FieldDescriptor {
  139. switch s.kind {
  140. case FieldAccessStep:
  141. return s.desc.(protoreflect.FieldDescriptor)
  142. default:
  143. return nil
  144. }
  145. }
  146. // ListIndex returns the list index for ListIndex steps,
  147. // otherwise it returns 0.
  148. func (s Step) ListIndex() int {
  149. switch s.kind {
  150. case ListIndexStep:
  151. return int(s.key.Int())
  152. default:
  153. return 0
  154. }
  155. }
  156. // MapIndex returns the map key for MapIndex steps,
  157. // otherwise it returns an invalid map key.
  158. func (s Step) MapIndex() protoreflect.MapKey {
  159. switch s.kind {
  160. case MapIndexStep:
  161. return s.key.MapKey()
  162. default:
  163. return protoreflect.MapKey{}
  164. }
  165. }
  166. // Kind reports which kind of step this is.
  167. func (s Step) Kind() StepKind {
  168. return s.kind
  169. }
  170. func (s Step) String() string {
  171. return string(s.appendString(nil))
  172. }
  173. func (s Step) appendString(b []byte) []byte {
  174. switch s.kind {
  175. case RootStep:
  176. b = append(b, '(')
  177. b = append(b, s.desc.FullName()...)
  178. b = append(b, ')')
  179. case FieldAccessStep:
  180. b = append(b, '.')
  181. if fd := s.desc.(protoreflect.FieldDescriptor); fd.IsExtension() {
  182. b = append(b, '(')
  183. b = append(b, strings.Trim(fd.TextName(), "[]")...)
  184. b = append(b, ')')
  185. } else {
  186. b = append(b, fd.TextName()...)
  187. }
  188. case UnknownAccessStep:
  189. b = append(b, '.')
  190. b = append(b, '?')
  191. case ListIndexStep:
  192. b = append(b, '[')
  193. b = strconv.AppendInt(b, s.key.Int(), 10)
  194. b = append(b, ']')
  195. case MapIndexStep:
  196. b = append(b, '[')
  197. switch k := s.key.Interface().(type) {
  198. case bool:
  199. b = strconv.AppendBool(b, bool(k)) // e.g., "true" or "false"
  200. case int32:
  201. b = strconv.AppendInt(b, int64(k), 10) // e.g., "-32"
  202. case int64:
  203. b = strconv.AppendInt(b, int64(k), 10) // e.g., "-64"
  204. case uint32:
  205. b = strconv.AppendUint(b, uint64(k), 10) // e.g., "32"
  206. case uint64:
  207. b = strconv.AppendUint(b, uint64(k), 10) // e.g., "64"
  208. case string:
  209. b = text.AppendString(b, k) // e.g., `"hello, world"`
  210. }
  211. b = append(b, ']')
  212. case AnyExpandStep:
  213. b = append(b, '.')
  214. b = append(b, '(')
  215. b = append(b, s.desc.FullName()...)
  216. b = append(b, ')')
  217. default:
  218. b = append(b, "<invalid>"...)
  219. }
  220. return b
  221. }