properties.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright 2010 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. import (
  6. "fmt"
  7. "reflect"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. protoV2 "google.golang.org/protobuf/proto"
  12. "google.golang.org/protobuf/runtime/protoimpl"
  13. )
  14. // Constants that identify the encoding of a value on the wire.
  15. const (
  16. WireVarint = 0
  17. WireFixed32 = 5
  18. WireFixed64 = 1
  19. WireBytes = 2
  20. WireStartGroup = 3
  21. WireEndGroup = 4
  22. )
  23. // StructProperties represents protocol buffer type information for a
  24. // generated protobuf message in the open-struct API.
  25. //
  26. // Deprecated: Do not use.
  27. type StructProperties struct {
  28. // Prop are the properties for each field.
  29. //
  30. // Fields belonging to a oneof are stored in OneofTypes instead, with a
  31. // single Properties representing the parent oneof held here.
  32. //
  33. // The order of Prop matches the order of fields in the Go struct.
  34. // Struct fields that are not related to protobufs have a "XXX_" prefix
  35. // in the Properties.Name and must be ignored by the user.
  36. Prop []*Properties
  37. // OneofTypes contains information about the oneof fields in this message.
  38. // It is keyed by the protobuf field name.
  39. OneofTypes map[string]*OneofProperties
  40. }
  41. // Properties represents the type information for a protobuf message field.
  42. //
  43. // Deprecated: Do not use.
  44. type Properties struct {
  45. // Name is a placeholder name with little meaningful semantic value.
  46. // Fields with an "XXX_" prefix must be ignored.
  47. Name string
  48. // OrigName is the protobuf field name or oneof name.
  49. OrigName string
  50. // JSONName is the JSON name for the protobuf field.
  51. JSONName string
  52. // Enum is a placeholder name for enums.
  53. // For historical reasons, this is neither the Go name for the enum,
  54. // nor the protobuf name for the enum.
  55. Enum string // Deprecated: Do not use.
  56. // Wire is a string representation of the wire type.
  57. Wire string
  58. // WireType is the protobuf wire type for the field.
  59. WireType int
  60. // Tag is the protobuf field number.
  61. Tag int
  62. // Required reports whether this is a required field.
  63. Required bool
  64. // Optional reports whether this is a optional field.
  65. Optional bool
  66. // Repeated reports whether this is a repeated field.
  67. Repeated bool
  68. // Packed reports whether this is a packed repeated field of scalars.
  69. Packed bool
  70. // Proto3 reports whether this field operates under the proto3 syntax.
  71. Proto3 bool
  72. // Oneof reports whether this field belongs within a oneof.
  73. Oneof bool
  74. // Default is the default value in string form.
  75. Default string
  76. // HasDefault reports whether the field has a default value.
  77. HasDefault bool
  78. // MapKeyProp is the properties for the key field for a map field.
  79. MapKeyProp *Properties
  80. // MapValProp is the properties for the value field for a map field.
  81. MapValProp *Properties
  82. }
  83. // OneofProperties represents the type information for a protobuf oneof.
  84. //
  85. // Deprecated: Do not use.
  86. type OneofProperties struct {
  87. // Type is a pointer to the generated wrapper type for the field value.
  88. // This is nil for messages that are not in the open-struct API.
  89. Type reflect.Type
  90. // Field is the index into StructProperties.Prop for the containing oneof.
  91. Field int
  92. // Prop is the properties for the field.
  93. Prop *Properties
  94. }
  95. // String formats the properties in the protobuf struct field tag style.
  96. func (p *Properties) String() string {
  97. s := p.Wire
  98. s += "," + strconv.Itoa(p.Tag)
  99. if p.Required {
  100. s += ",req"
  101. }
  102. if p.Optional {
  103. s += ",opt"
  104. }
  105. if p.Repeated {
  106. s += ",rep"
  107. }
  108. if p.Packed {
  109. s += ",packed"
  110. }
  111. s += ",name=" + p.OrigName
  112. if p.JSONName != "" {
  113. s += ",json=" + p.JSONName
  114. }
  115. if p.Proto3 {
  116. s += ",proto3"
  117. }
  118. if p.Oneof {
  119. s += ",oneof"
  120. }
  121. if len(p.Enum) > 0 {
  122. s += ",enum=" + p.Enum
  123. }
  124. if p.HasDefault {
  125. s += ",def=" + p.Default
  126. }
  127. return s
  128. }
  129. // Parse populates p by parsing a string in the protobuf struct field tag style.
  130. func (p *Properties) Parse(tag string) {
  131. // For example: "bytes,49,opt,name=foo,def=hello!"
  132. for len(tag) > 0 {
  133. i := strings.IndexByte(tag, ',')
  134. if i < 0 {
  135. i = len(tag)
  136. }
  137. switch s := tag[:i]; {
  138. case strings.HasPrefix(s, "name="):
  139. p.OrigName = s[len("name="):]
  140. case strings.HasPrefix(s, "json="):
  141. p.JSONName = s[len("json="):]
  142. case strings.HasPrefix(s, "enum="):
  143. p.Enum = s[len("enum="):]
  144. case strings.Trim(s, "0123456789") == "":
  145. n, _ := strconv.ParseUint(s, 10, 32)
  146. p.Tag = int(n)
  147. case s == "opt":
  148. p.Optional = true
  149. case s == "req":
  150. p.Required = true
  151. case s == "rep":
  152. p.Repeated = true
  153. case s == "varint" || s == "zigzag32" || s == "zigzag64":
  154. p.Wire = s
  155. p.WireType = WireVarint
  156. case s == "fixed32":
  157. p.Wire = s
  158. p.WireType = WireFixed32
  159. case s == "fixed64":
  160. p.Wire = s
  161. p.WireType = WireFixed64
  162. case s == "bytes":
  163. p.Wire = s
  164. p.WireType = WireBytes
  165. case s == "group":
  166. p.Wire = s
  167. p.WireType = WireStartGroup
  168. case s == "packed":
  169. p.Packed = true
  170. case s == "proto3":
  171. p.Proto3 = true
  172. case s == "oneof":
  173. p.Oneof = true
  174. case strings.HasPrefix(s, "def="):
  175. // The default tag is special in that everything afterwards is the
  176. // default regardless of the presence of commas.
  177. p.HasDefault = true
  178. p.Default, i = tag[len("def="):], len(tag)
  179. }
  180. tag = strings.TrimPrefix(tag[i:], ",")
  181. }
  182. }
  183. // Init populates the properties from a protocol buffer struct tag.
  184. //
  185. // Deprecated: Do not use.
  186. func (p *Properties) Init(typ reflect.Type, name, tag string, f *reflect.StructField) {
  187. p.init(typ, name, tag, f)
  188. }
  189. func (p *Properties) init(typ reflect.Type, name, tag string, f *reflect.StructField) {
  190. p.Name = name
  191. p.OrigName = name
  192. if tag == "" {
  193. return
  194. }
  195. p.Parse(tag)
  196. if typ != nil && typ.Kind() == reflect.Map {
  197. p.MapKeyProp = new(Properties)
  198. p.MapKeyProp.init(nil, "Key", f.Tag.Get("protobuf_key"), nil)
  199. p.MapValProp = new(Properties)
  200. p.MapValProp.init(nil, "Value", f.Tag.Get("protobuf_val"), nil)
  201. }
  202. }
  203. var propertiesCache sync.Map // map[reflect.Type]*StructProperties
  204. // GetProperties returns the list of properties for the type represented by t,
  205. // which must be a generated protocol buffer message in the open-struct API,
  206. // where protobuf message fields are represented by exported Go struct fields.
  207. //
  208. // Deprecated: Use v2 protobuf reflection instead.
  209. func GetProperties(t reflect.Type) *StructProperties {
  210. if p, ok := propertiesCache.Load(t); ok {
  211. return p.(*StructProperties)
  212. }
  213. p, _ := propertiesCache.LoadOrStore(t, newProperties(t))
  214. return p.(*StructProperties)
  215. }
  216. func newProperties(t reflect.Type) *StructProperties {
  217. if t.Kind() != reflect.Struct {
  218. panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
  219. }
  220. var foundField bool
  221. prop := new(StructProperties)
  222. // Construct a list of properties for each field in the struct.
  223. for i := 0; i < t.NumField(); i++ {
  224. p := new(Properties)
  225. f := t.Field(i)
  226. tagField := f.Tag.Get("protobuf")
  227. p.init(f.Type, f.Name, tagField, &f)
  228. foundField = foundField || p.Tag > 0
  229. tagOneof := f.Tag.Get("protobuf_oneof")
  230. if tagOneof != "" {
  231. p.OrigName = tagOneof
  232. }
  233. // Rename unexported struct fields with the "XXX_" prefix since so much
  234. // user code simply checks for this to exclude unrelated fields.
  235. if f.PkgPath != "" {
  236. p.Name = "XXX_" + p.Name
  237. }
  238. prop.Prop = append(prop.Prop, p)
  239. }
  240. // Construct a mapping of oneof field names to properties.
  241. var oneofWrappers []interface{}
  242. if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofFuncs"); ok {
  243. oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[3].Interface().([]interface{})
  244. }
  245. if fn, ok := reflect.PtrTo(t).MethodByName("XXX_OneofWrappers"); ok {
  246. oneofWrappers = fn.Func.Call([]reflect.Value{reflect.Zero(fn.Type.In(0))})[0].Interface().([]interface{})
  247. }
  248. if m, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(protoV2.Message); ok {
  249. if m, ok := m.ProtoReflect().(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok {
  250. oneofWrappers = m.ProtoMessageInfo().OneofWrappers
  251. }
  252. }
  253. if len(oneofWrappers) > 0 {
  254. prop.OneofTypes = make(map[string]*OneofProperties)
  255. for _, wrapper := range oneofWrappers {
  256. p := &OneofProperties{
  257. Type: reflect.ValueOf(wrapper).Type(), // *T
  258. Prop: new(Properties),
  259. }
  260. f := p.Type.Elem().Field(0)
  261. p.Prop.Name = f.Name
  262. p.Prop.Parse(f.Tag.Get("protobuf"))
  263. foundField = foundField || p.Prop.Tag > 0
  264. // Determine the struct field that contains this oneof.
  265. // Each wrapper is assignable to exactly one parent field.
  266. var foundOneof bool
  267. for i := 0; i < t.NumField() && !foundOneof; i++ {
  268. if p.Type.AssignableTo(t.Field(i).Type) {
  269. p.Field = i
  270. foundOneof = true
  271. }
  272. }
  273. if !foundOneof {
  274. panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
  275. }
  276. prop.OneofTypes[p.Prop.OrigName] = p
  277. }
  278. }
  279. // If we found no fields, it is possible that the struct uses a
  280. // generated API that is not an open-struct layout.
  281. if !foundField {
  282. // Check with protobuf reflection to make sure this isn't
  283. // an empty protobuf message.
  284. mt := protoimpl.X.MessageDescriptorOf(reflect.New(t).Interface())
  285. if mt.Fields().Len() > 0 {
  286. panic(fmt.Sprintf("%v is not a generated message in the open-struct API", t))
  287. }
  288. }
  289. return prop
  290. }
  291. func (sp *StructProperties) Len() int { return len(sp.Prop) }
  292. func (sp *StructProperties) Less(i, j int) bool { return false }
  293. func (sp *StructProperties) Swap(i, j int) { return }