message_reflect_field.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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 impl
  5. import (
  6. "fmt"
  7. "math"
  8. "reflect"
  9. "google.golang.org/protobuf/reflect/protoreflect"
  10. )
  11. type fieldInfo struct {
  12. fieldDesc protoreflect.FieldDescriptor
  13. // These fields are used for protobuf reflection support.
  14. has func(pointer) bool
  15. clear func(pointer)
  16. get func(pointer) protoreflect.Value
  17. set func(pointer, protoreflect.Value)
  18. mutable func(pointer) protoreflect.Value
  19. newMessage func() protoreflect.Message
  20. newField func() protoreflect.Value
  21. }
  22. func fieldInfoForMissing(fd protoreflect.FieldDescriptor) fieldInfo {
  23. // This never occurs for generated message types.
  24. // It implies that a hand-crafted type has missing Go fields
  25. // for specific protobuf message fields.
  26. return fieldInfo{
  27. fieldDesc: fd,
  28. has: func(p pointer) bool {
  29. return false
  30. },
  31. clear: func(p pointer) {
  32. panic("missing Go struct field for " + string(fd.FullName()))
  33. },
  34. get: func(p pointer) protoreflect.Value {
  35. return fd.Default()
  36. },
  37. set: func(p pointer, v protoreflect.Value) {
  38. panic("missing Go struct field for " + string(fd.FullName()))
  39. },
  40. mutable: func(p pointer) protoreflect.Value {
  41. panic("missing Go struct field for " + string(fd.FullName()))
  42. },
  43. newMessage: func() protoreflect.Message {
  44. panic("missing Go struct field for " + string(fd.FullName()))
  45. },
  46. newField: func() protoreflect.Value {
  47. if v := fd.Default(); v.IsValid() {
  48. return v
  49. }
  50. panic("missing Go struct field for " + string(fd.FullName()))
  51. },
  52. }
  53. }
  54. func fieldInfoForOneof(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
  55. ft := fs.Type
  56. if ft.Kind() != reflect.Interface {
  57. panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", fd.FullName(), ft))
  58. }
  59. if ot.Kind() != reflect.Struct {
  60. panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", fd.FullName(), ot))
  61. }
  62. if !reflect.PtrTo(ot).Implements(ft) {
  63. panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", fd.FullName(), ot, ft))
  64. }
  65. conv := NewConverter(ot.Field(0).Type, fd)
  66. isMessage := fd.Message() != nil
  67. // TODO: Implement unsafe fast path?
  68. fieldOffset := offsetOf(fs)
  69. return fieldInfo{
  70. // NOTE: The logic below intentionally assumes that oneof fields are
  71. // well-formatted. That is, the oneof interface never contains a
  72. // typed nil pointer to one of the wrapper structs.
  73. fieldDesc: fd,
  74. has: func(p pointer) bool {
  75. if p.IsNil() {
  76. return false
  77. }
  78. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  79. if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
  80. return false
  81. }
  82. return true
  83. },
  84. clear: func(p pointer) {
  85. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  86. if rv.IsNil() || rv.Elem().Type().Elem() != ot {
  87. // NOTE: We intentionally don't check for rv.Elem().IsNil()
  88. // so that (*OneofWrapperType)(nil) gets cleared to nil.
  89. return
  90. }
  91. rv.Set(reflect.Zero(rv.Type()))
  92. },
  93. get: func(p pointer) protoreflect.Value {
  94. if p.IsNil() {
  95. return conv.Zero()
  96. }
  97. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  98. if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
  99. return conv.Zero()
  100. }
  101. rv = rv.Elem().Elem().Field(0)
  102. return conv.PBValueOf(rv)
  103. },
  104. set: func(p pointer, v protoreflect.Value) {
  105. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  106. if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
  107. rv.Set(reflect.New(ot))
  108. }
  109. rv = rv.Elem().Elem().Field(0)
  110. rv.Set(conv.GoValueOf(v))
  111. },
  112. mutable: func(p pointer) protoreflect.Value {
  113. if !isMessage {
  114. panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", fd.FullName()))
  115. }
  116. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  117. if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
  118. rv.Set(reflect.New(ot))
  119. }
  120. rv = rv.Elem().Elem().Field(0)
  121. if rv.Kind() == reflect.Ptr && rv.IsNil() {
  122. rv.Set(conv.GoValueOf(protoreflect.ValueOfMessage(conv.New().Message())))
  123. }
  124. return conv.PBValueOf(rv)
  125. },
  126. newMessage: func() protoreflect.Message {
  127. return conv.New().Message()
  128. },
  129. newField: func() protoreflect.Value {
  130. return conv.New()
  131. },
  132. }
  133. }
  134. func fieldInfoForMap(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
  135. ft := fs.Type
  136. if ft.Kind() != reflect.Map {
  137. panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", fd.FullName(), ft))
  138. }
  139. conv := NewConverter(ft, fd)
  140. // TODO: Implement unsafe fast path?
  141. fieldOffset := offsetOf(fs)
  142. return fieldInfo{
  143. fieldDesc: fd,
  144. has: func(p pointer) bool {
  145. if p.IsNil() {
  146. return false
  147. }
  148. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  149. return rv.Len() > 0
  150. },
  151. clear: func(p pointer) {
  152. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  153. rv.Set(reflect.Zero(rv.Type()))
  154. },
  155. get: func(p pointer) protoreflect.Value {
  156. if p.IsNil() {
  157. return conv.Zero()
  158. }
  159. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  160. if rv.Len() == 0 {
  161. return conv.Zero()
  162. }
  163. return conv.PBValueOf(rv)
  164. },
  165. set: func(p pointer, v protoreflect.Value) {
  166. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  167. pv := conv.GoValueOf(v)
  168. if pv.IsNil() {
  169. panic(fmt.Sprintf("map field %v cannot be set with read-only value", fd.FullName()))
  170. }
  171. rv.Set(pv)
  172. },
  173. mutable: func(p pointer) protoreflect.Value {
  174. v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  175. if v.IsNil() {
  176. v.Set(reflect.MakeMap(fs.Type))
  177. }
  178. return conv.PBValueOf(v)
  179. },
  180. newField: func() protoreflect.Value {
  181. return conv.New()
  182. },
  183. }
  184. }
  185. func fieldInfoForList(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
  186. ft := fs.Type
  187. if ft.Kind() != reflect.Slice {
  188. panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", fd.FullName(), ft))
  189. }
  190. conv := NewConverter(reflect.PtrTo(ft), fd)
  191. // TODO: Implement unsafe fast path?
  192. fieldOffset := offsetOf(fs)
  193. return fieldInfo{
  194. fieldDesc: fd,
  195. has: func(p pointer) bool {
  196. if p.IsNil() {
  197. return false
  198. }
  199. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  200. return rv.Len() > 0
  201. },
  202. clear: func(p pointer) {
  203. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  204. rv.Set(reflect.Zero(rv.Type()))
  205. },
  206. get: func(p pointer) protoreflect.Value {
  207. if p.IsNil() {
  208. return conv.Zero()
  209. }
  210. rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
  211. if rv.Elem().Len() == 0 {
  212. return conv.Zero()
  213. }
  214. return conv.PBValueOf(rv)
  215. },
  216. set: func(p pointer, v protoreflect.Value) {
  217. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  218. pv := conv.GoValueOf(v)
  219. if pv.IsNil() {
  220. panic(fmt.Sprintf("list field %v cannot be set with read-only value", fd.FullName()))
  221. }
  222. rv.Set(pv.Elem())
  223. },
  224. mutable: func(p pointer) protoreflect.Value {
  225. v := p.Apply(fieldOffset).AsValueOf(fs.Type)
  226. return conv.PBValueOf(v)
  227. },
  228. newField: func() protoreflect.Value {
  229. return conv.New()
  230. },
  231. }
  232. }
  233. var (
  234. nilBytes = reflect.ValueOf([]byte(nil))
  235. emptyBytes = reflect.ValueOf([]byte{})
  236. )
  237. func fieldInfoForScalar(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
  238. ft := fs.Type
  239. nullable := fd.HasPresence()
  240. isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
  241. var getter func(p pointer) protoreflect.Value
  242. if nullable {
  243. if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
  244. // This never occurs for generated message types.
  245. // Despite the protobuf type system specifying presence,
  246. // the Go field type cannot represent it.
  247. nullable = false
  248. }
  249. if ft.Kind() == reflect.Ptr {
  250. ft = ft.Elem()
  251. }
  252. }
  253. conv := NewConverter(ft, fd)
  254. fieldOffset := offsetOf(fs)
  255. // Generate specialized getter functions to avoid going through reflect.Value
  256. if nullable {
  257. getter = getterForNullableScalar(fd, fs, conv, fieldOffset)
  258. } else {
  259. getter = getterForDirectScalar(fd, fs, conv, fieldOffset)
  260. }
  261. return fieldInfo{
  262. fieldDesc: fd,
  263. has: func(p pointer) bool {
  264. if p.IsNil() {
  265. return false
  266. }
  267. if nullable {
  268. return !p.Apply(fieldOffset).Elem().IsNil()
  269. }
  270. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  271. switch rv.Kind() {
  272. case reflect.Bool:
  273. return rv.Bool()
  274. case reflect.Int32, reflect.Int64:
  275. return rv.Int() != 0
  276. case reflect.Uint32, reflect.Uint64:
  277. return rv.Uint() != 0
  278. case reflect.Float32, reflect.Float64:
  279. return rv.Float() != 0 || math.Signbit(rv.Float())
  280. case reflect.String, reflect.Slice:
  281. return rv.Len() > 0
  282. default:
  283. panic(fmt.Sprintf("field %v has invalid type: %v", fd.FullName(), rv.Type())) // should never happen
  284. }
  285. },
  286. clear: func(p pointer) {
  287. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  288. rv.Set(reflect.Zero(rv.Type()))
  289. },
  290. get: getter,
  291. // TODO: Implement unsafe fast path for set?
  292. set: func(p pointer, v protoreflect.Value) {
  293. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  294. if nullable && rv.Kind() == reflect.Ptr {
  295. if rv.IsNil() {
  296. rv.Set(reflect.New(ft))
  297. }
  298. rv = rv.Elem()
  299. }
  300. rv.Set(conv.GoValueOf(v))
  301. if isBytes && rv.Len() == 0 {
  302. if nullable {
  303. rv.Set(emptyBytes) // preserve presence
  304. } else {
  305. rv.Set(nilBytes) // do not preserve presence
  306. }
  307. }
  308. },
  309. newField: func() protoreflect.Value {
  310. return conv.New()
  311. },
  312. }
  313. }
  314. func fieldInfoForMessage(fd protoreflect.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
  315. ft := fs.Type
  316. conv := NewConverter(ft, fd)
  317. // TODO: Implement unsafe fast path?
  318. fieldOffset := offsetOf(fs)
  319. return fieldInfo{
  320. fieldDesc: fd,
  321. has: func(p pointer) bool {
  322. if p.IsNil() {
  323. return false
  324. }
  325. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  326. if fs.Type.Kind() != reflect.Ptr {
  327. return !rv.IsZero()
  328. }
  329. return !rv.IsNil()
  330. },
  331. clear: func(p pointer) {
  332. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  333. rv.Set(reflect.Zero(rv.Type()))
  334. },
  335. get: func(p pointer) protoreflect.Value {
  336. if p.IsNil() {
  337. return conv.Zero()
  338. }
  339. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  340. return conv.PBValueOf(rv)
  341. },
  342. set: func(p pointer, v protoreflect.Value) {
  343. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  344. rv.Set(conv.GoValueOf(v))
  345. if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
  346. panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName()))
  347. }
  348. },
  349. mutable: func(p pointer) protoreflect.Value {
  350. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  351. if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
  352. rv.Set(conv.GoValueOf(conv.New()))
  353. }
  354. return conv.PBValueOf(rv)
  355. },
  356. newMessage: func() protoreflect.Message {
  357. return conv.New().Message()
  358. },
  359. newField: func() protoreflect.Value {
  360. return conv.New()
  361. },
  362. }
  363. }
  364. type oneofInfo struct {
  365. oneofDesc protoreflect.OneofDescriptor
  366. which func(pointer) protoreflect.FieldNumber
  367. }
  368. func makeOneofInfo(od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
  369. oi := &oneofInfo{oneofDesc: od}
  370. if od.IsSynthetic() {
  371. fs := si.fieldsByNumber[od.Fields().Get(0).Number()]
  372. fieldOffset := offsetOf(fs)
  373. oi.which = func(p pointer) protoreflect.FieldNumber {
  374. if p.IsNil() {
  375. return 0
  376. }
  377. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  378. if rv.IsNil() { // valid on either *T or []byte
  379. return 0
  380. }
  381. return od.Fields().Get(0).Number()
  382. }
  383. } else {
  384. fs := si.oneofsByName[od.Name()]
  385. fieldOffset := offsetOf(fs)
  386. oi.which = func(p pointer) protoreflect.FieldNumber {
  387. if p.IsNil() {
  388. return 0
  389. }
  390. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  391. if rv.IsNil() {
  392. return 0
  393. }
  394. rv = rv.Elem()
  395. if rv.IsNil() {
  396. return 0
  397. }
  398. return si.oneofWrappersByType[rv.Type().Elem()]
  399. }
  400. }
  401. return oi
  402. }