Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

307 рядки
8.9 KiB

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