message_opaque.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. // Copyright 2024 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. "strings"
  10. "sync/atomic"
  11. "google.golang.org/protobuf/reflect/protoreflect"
  12. )
  13. type opaqueStructInfo struct {
  14. structInfo
  15. }
  16. // isOpaque determines whether a protobuf message type is on the Opaque API. It
  17. // checks whether the type is a Go struct that protoc-gen-go would generate.
  18. //
  19. // This function only detects newly generated messages from the v2
  20. // implementation of protoc-gen-go. It is unable to classify generated messages
  21. // that are too old or those that are generated by a different generator
  22. // such as protoc-gen-gogo.
  23. func isOpaque(t reflect.Type) bool {
  24. // The current detection mechanism is to simply check the first field
  25. // for a struct tag with the "protogen" key.
  26. if t.Kind() == reflect.Struct && t.NumField() > 0 {
  27. pgt := t.Field(0).Tag.Get("protogen")
  28. return strings.HasPrefix(pgt, "opaque.")
  29. }
  30. return false
  31. }
  32. func opaqueInitHook(mi *MessageInfo) bool {
  33. mt := mi.GoReflectType.Elem()
  34. si := opaqueStructInfo{
  35. structInfo: mi.makeStructInfo(mt),
  36. }
  37. if !isOpaque(mt) {
  38. return false
  39. }
  40. defer atomic.StoreUint32(&mi.initDone, 1)
  41. mi.fields = map[protoreflect.FieldNumber]*fieldInfo{}
  42. fds := mi.Desc.Fields()
  43. for i := 0; i < fds.Len(); i++ {
  44. fd := fds.Get(i)
  45. fs := si.fieldsByNumber[fd.Number()]
  46. var fi fieldInfo
  47. usePresence, _ := usePresenceForField(si, fd)
  48. switch {
  49. case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
  50. // Oneofs are no different for opaque.
  51. fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], mi.Exporter, si.oneofWrappersByNumber[fd.Number()])
  52. case fd.IsMap():
  53. fi = mi.fieldInfoForMapOpaque(si, fd, fs)
  54. case fd.IsList() && fd.Message() == nil && usePresence:
  55. fi = mi.fieldInfoForScalarListOpaque(si, fd, fs)
  56. case fd.IsList() && fd.Message() == nil:
  57. // Proto3 lists without presence can use same access methods as open
  58. fi = fieldInfoForList(fd, fs, mi.Exporter)
  59. case fd.IsList() && usePresence:
  60. fi = mi.fieldInfoForMessageListOpaque(si, fd, fs)
  61. case fd.IsList():
  62. // Proto3 opaque messages that does not need presence bitmap.
  63. // Different representation than open struct, but same logic
  64. fi = mi.fieldInfoForMessageListOpaqueNoPresence(si, fd, fs)
  65. case fd.Message() != nil && usePresence:
  66. fi = mi.fieldInfoForMessageOpaque(si, fd, fs)
  67. case fd.Message() != nil:
  68. // Proto3 messages without presence can use same access methods as open
  69. fi = fieldInfoForMessage(fd, fs, mi.Exporter)
  70. default:
  71. fi = mi.fieldInfoForScalarOpaque(si, fd, fs)
  72. }
  73. mi.fields[fd.Number()] = &fi
  74. }
  75. mi.oneofs = map[protoreflect.Name]*oneofInfo{}
  76. for i := 0; i < mi.Desc.Oneofs().Len(); i++ {
  77. od := mi.Desc.Oneofs().Get(i)
  78. mi.oneofs[od.Name()] = makeOneofInfoOpaque(mi, od, si.structInfo, mi.Exporter)
  79. }
  80. mi.denseFields = make([]*fieldInfo, fds.Len()*2)
  81. for i := 0; i < fds.Len(); i++ {
  82. if fd := fds.Get(i); int(fd.Number()) < len(mi.denseFields) {
  83. mi.denseFields[fd.Number()] = mi.fields[fd.Number()]
  84. }
  85. }
  86. for i := 0; i < fds.Len(); {
  87. fd := fds.Get(i)
  88. if od := fd.ContainingOneof(); od != nil && !fd.ContainingOneof().IsSynthetic() {
  89. mi.rangeInfos = append(mi.rangeInfos, mi.oneofs[od.Name()])
  90. i += od.Fields().Len()
  91. } else {
  92. mi.rangeInfos = append(mi.rangeInfos, mi.fields[fd.Number()])
  93. i++
  94. }
  95. }
  96. mi.makeExtensionFieldsFunc(mt, si.structInfo)
  97. mi.makeUnknownFieldsFunc(mt, si.structInfo)
  98. mi.makeOpaqueCoderMethods(mt, si)
  99. mi.makeFieldTypes(si.structInfo)
  100. return true
  101. }
  102. func makeOneofInfoOpaque(mi *MessageInfo, od protoreflect.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
  103. oi := &oneofInfo{oneofDesc: od}
  104. if od.IsSynthetic() {
  105. fd := od.Fields().Get(0)
  106. index, _ := presenceIndex(mi.Desc, fd)
  107. oi.which = func(p pointer) protoreflect.FieldNumber {
  108. if p.IsNil() {
  109. return 0
  110. }
  111. if !mi.present(p, index) {
  112. return 0
  113. }
  114. return od.Fields().Get(0).Number()
  115. }
  116. return oi
  117. }
  118. // Dispatch to non-opaque oneof implementation for non-synthetic oneofs.
  119. return makeOneofInfo(od, si, x)
  120. }
  121. func (mi *MessageInfo) fieldInfoForMapOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
  122. ft := fs.Type
  123. if ft.Kind() != reflect.Map {
  124. panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
  125. }
  126. fieldOffset := offsetOf(fs)
  127. conv := NewConverter(ft, fd)
  128. return fieldInfo{
  129. fieldDesc: fd,
  130. has: func(p pointer) bool {
  131. if p.IsNil() {
  132. return false
  133. }
  134. // Don't bother checking presence bits, since we need to
  135. // look at the map length even if the presence bit is set.
  136. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  137. return rv.Len() > 0
  138. },
  139. clear: func(p pointer) {
  140. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  141. rv.Set(reflect.Zero(rv.Type()))
  142. },
  143. get: func(p pointer) protoreflect.Value {
  144. if p.IsNil() {
  145. return conv.Zero()
  146. }
  147. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  148. if rv.Len() == 0 {
  149. return conv.Zero()
  150. }
  151. return conv.PBValueOf(rv)
  152. },
  153. set: func(p pointer, v protoreflect.Value) {
  154. pv := conv.GoValueOf(v)
  155. if pv.IsNil() {
  156. panic(fmt.Sprintf("invalid value: setting map field to read-only value"))
  157. }
  158. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  159. rv.Set(pv)
  160. },
  161. mutable: func(p pointer) protoreflect.Value {
  162. v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  163. if v.IsNil() {
  164. v.Set(reflect.MakeMap(fs.Type))
  165. }
  166. return conv.PBValueOf(v)
  167. },
  168. newField: func() protoreflect.Value {
  169. return conv.New()
  170. },
  171. }
  172. }
  173. func (mi *MessageInfo) fieldInfoForScalarListOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
  174. ft := fs.Type
  175. if ft.Kind() != reflect.Slice {
  176. panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
  177. }
  178. conv := NewConverter(reflect.PtrTo(ft), fd)
  179. fieldOffset := offsetOf(fs)
  180. index, _ := presenceIndex(mi.Desc, fd)
  181. return fieldInfo{
  182. fieldDesc: fd,
  183. has: func(p pointer) bool {
  184. if p.IsNil() {
  185. return false
  186. }
  187. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  188. return rv.Len() > 0
  189. },
  190. clear: func(p pointer) {
  191. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  192. rv.Set(reflect.Zero(rv.Type()))
  193. },
  194. get: func(p pointer) protoreflect.Value {
  195. if p.IsNil() {
  196. return conv.Zero()
  197. }
  198. rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
  199. if rv.Elem().Len() == 0 {
  200. return conv.Zero()
  201. }
  202. return conv.PBValueOf(rv)
  203. },
  204. set: func(p pointer, v protoreflect.Value) {
  205. pv := conv.GoValueOf(v)
  206. if pv.IsNil() {
  207. panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
  208. }
  209. mi.setPresent(p, index)
  210. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  211. rv.Set(pv.Elem())
  212. },
  213. mutable: func(p pointer) protoreflect.Value {
  214. mi.setPresent(p, index)
  215. return conv.PBValueOf(p.Apply(fieldOffset).AsValueOf(fs.Type))
  216. },
  217. newField: func() protoreflect.Value {
  218. return conv.New()
  219. },
  220. }
  221. }
  222. func (mi *MessageInfo) fieldInfoForMessageListOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
  223. ft := fs.Type
  224. if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
  225. panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
  226. }
  227. conv := NewConverter(ft, fd)
  228. fieldOffset := offsetOf(fs)
  229. index, _ := presenceIndex(mi.Desc, fd)
  230. fieldNumber := fd.Number()
  231. return fieldInfo{
  232. fieldDesc: fd,
  233. has: func(p pointer) bool {
  234. if p.IsNil() {
  235. return false
  236. }
  237. if !mi.present(p, index) {
  238. return false
  239. }
  240. sp := p.Apply(fieldOffset).AtomicGetPointer()
  241. if sp.IsNil() {
  242. // Lazily unmarshal this field.
  243. mi.lazyUnmarshal(p, fieldNumber)
  244. sp = p.Apply(fieldOffset).AtomicGetPointer()
  245. }
  246. rv := sp.AsValueOf(fs.Type.Elem())
  247. return rv.Elem().Len() > 0
  248. },
  249. clear: func(p pointer) {
  250. fp := p.Apply(fieldOffset)
  251. sp := fp.AtomicGetPointer()
  252. if sp.IsNil() {
  253. sp = fp.AtomicSetPointerIfNil(pointerOfValue(reflect.New(fs.Type.Elem())))
  254. mi.setPresent(p, index)
  255. }
  256. rv := sp.AsValueOf(fs.Type.Elem())
  257. rv.Elem().Set(reflect.Zero(rv.Type().Elem()))
  258. },
  259. get: func(p pointer) protoreflect.Value {
  260. if p.IsNil() {
  261. return conv.Zero()
  262. }
  263. if !mi.present(p, index) {
  264. return conv.Zero()
  265. }
  266. sp := p.Apply(fieldOffset).AtomicGetPointer()
  267. if sp.IsNil() {
  268. // Lazily unmarshal this field.
  269. mi.lazyUnmarshal(p, fieldNumber)
  270. sp = p.Apply(fieldOffset).AtomicGetPointer()
  271. }
  272. rv := sp.AsValueOf(fs.Type.Elem())
  273. if rv.Elem().Len() == 0 {
  274. return conv.Zero()
  275. }
  276. return conv.PBValueOf(rv)
  277. },
  278. set: func(p pointer, v protoreflect.Value) {
  279. fp := p.Apply(fieldOffset)
  280. sp := fp.AtomicGetPointer()
  281. if sp.IsNil() {
  282. sp = fp.AtomicSetPointerIfNil(pointerOfValue(reflect.New(fs.Type.Elem())))
  283. mi.setPresent(p, index)
  284. }
  285. rv := sp.AsValueOf(fs.Type.Elem())
  286. val := conv.GoValueOf(v)
  287. if val.IsNil() {
  288. panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
  289. } else {
  290. rv.Elem().Set(val.Elem())
  291. }
  292. },
  293. mutable: func(p pointer) protoreflect.Value {
  294. fp := p.Apply(fieldOffset)
  295. sp := fp.AtomicGetPointer()
  296. if sp.IsNil() {
  297. if mi.present(p, index) {
  298. // Lazily unmarshal this field.
  299. mi.lazyUnmarshal(p, fieldNumber)
  300. sp = p.Apply(fieldOffset).AtomicGetPointer()
  301. } else {
  302. sp = fp.AtomicSetPointerIfNil(pointerOfValue(reflect.New(fs.Type.Elem())))
  303. mi.setPresent(p, index)
  304. }
  305. }
  306. rv := sp.AsValueOf(fs.Type.Elem())
  307. return conv.PBValueOf(rv)
  308. },
  309. newField: func() protoreflect.Value {
  310. return conv.New()
  311. },
  312. }
  313. }
  314. func (mi *MessageInfo) fieldInfoForMessageListOpaqueNoPresence(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
  315. ft := fs.Type
  316. if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
  317. panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
  318. }
  319. conv := NewConverter(ft, fd)
  320. fieldOffset := offsetOf(fs)
  321. return fieldInfo{
  322. fieldDesc: fd,
  323. has: func(p pointer) bool {
  324. if p.IsNil() {
  325. return false
  326. }
  327. sp := p.Apply(fieldOffset).AtomicGetPointer()
  328. if sp.IsNil() {
  329. return false
  330. }
  331. rv := sp.AsValueOf(fs.Type.Elem())
  332. return rv.Elem().Len() > 0
  333. },
  334. clear: func(p pointer) {
  335. sp := p.Apply(fieldOffset).AtomicGetPointer()
  336. if !sp.IsNil() {
  337. rv := sp.AsValueOf(fs.Type.Elem())
  338. rv.Elem().Set(reflect.Zero(rv.Type().Elem()))
  339. }
  340. },
  341. get: func(p pointer) protoreflect.Value {
  342. if p.IsNil() {
  343. return conv.Zero()
  344. }
  345. sp := p.Apply(fieldOffset).AtomicGetPointer()
  346. if sp.IsNil() {
  347. return conv.Zero()
  348. }
  349. rv := sp.AsValueOf(fs.Type.Elem())
  350. if rv.Elem().Len() == 0 {
  351. return conv.Zero()
  352. }
  353. return conv.PBValueOf(rv)
  354. },
  355. set: func(p pointer, v protoreflect.Value) {
  356. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  357. if rv.IsNil() {
  358. rv.Set(reflect.New(fs.Type.Elem()))
  359. }
  360. val := conv.GoValueOf(v)
  361. if val.IsNil() {
  362. panic(fmt.Sprintf("invalid value: setting repeated field to read-only value"))
  363. } else {
  364. rv.Elem().Set(val.Elem())
  365. }
  366. },
  367. mutable: func(p pointer) protoreflect.Value {
  368. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  369. if rv.IsNil() {
  370. rv.Set(reflect.New(fs.Type.Elem()))
  371. }
  372. return conv.PBValueOf(rv)
  373. },
  374. newField: func() protoreflect.Value {
  375. return conv.New()
  376. },
  377. }
  378. }
  379. func (mi *MessageInfo) fieldInfoForScalarOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
  380. ft := fs.Type
  381. nullable := fd.HasPresence()
  382. if oneof := fd.ContainingOneof(); oneof != nil && oneof.IsSynthetic() {
  383. nullable = true
  384. }
  385. deref := false
  386. if nullable && ft.Kind() == reflect.Ptr {
  387. ft = ft.Elem()
  388. deref = true
  389. }
  390. conv := NewConverter(ft, fd)
  391. fieldOffset := offsetOf(fs)
  392. index, _ := presenceIndex(mi.Desc, fd)
  393. var getter func(p pointer) protoreflect.Value
  394. if !nullable {
  395. getter = getterForDirectScalar(fd, fs, conv, fieldOffset)
  396. } else {
  397. getter = getterForOpaqueNullableScalar(mi, index, fd, fs, conv, fieldOffset)
  398. }
  399. return fieldInfo{
  400. fieldDesc: fd,
  401. has: func(p pointer) bool {
  402. if p.IsNil() {
  403. return false
  404. }
  405. if nullable {
  406. return mi.present(p, index)
  407. }
  408. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  409. switch rv.Kind() {
  410. case reflect.Bool:
  411. return rv.Bool()
  412. case reflect.Int32, reflect.Int64:
  413. return rv.Int() != 0
  414. case reflect.Uint32, reflect.Uint64:
  415. return rv.Uint() != 0
  416. case reflect.Float32, reflect.Float64:
  417. return rv.Float() != 0 || math.Signbit(rv.Float())
  418. case reflect.String, reflect.Slice:
  419. return rv.Len() > 0
  420. default:
  421. panic(fmt.Sprintf("invalid type: %v", rv.Type())) // should never happen
  422. }
  423. },
  424. clear: func(p pointer) {
  425. if nullable {
  426. mi.clearPresent(p, index)
  427. }
  428. // This is only valuable for bytes and strings, but we do it unconditionally.
  429. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  430. rv.Set(reflect.Zero(rv.Type()))
  431. },
  432. get: getter,
  433. // TODO: Implement unsafe fast path for set?
  434. set: func(p pointer, v protoreflect.Value) {
  435. rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
  436. if deref {
  437. if rv.IsNil() {
  438. rv.Set(reflect.New(ft))
  439. }
  440. rv = rv.Elem()
  441. }
  442. rv.Set(conv.GoValueOf(v))
  443. if nullable && rv.Kind() == reflect.Slice && rv.IsNil() {
  444. rv.Set(emptyBytes)
  445. }
  446. if nullable {
  447. mi.setPresent(p, index)
  448. }
  449. },
  450. newField: func() protoreflect.Value {
  451. return conv.New()
  452. },
  453. }
  454. }
  455. func (mi *MessageInfo) fieldInfoForMessageOpaque(si opaqueStructInfo, fd protoreflect.FieldDescriptor, fs reflect.StructField) fieldInfo {
  456. ft := fs.Type
  457. conv := NewConverter(ft, fd)
  458. fieldOffset := offsetOf(fs)
  459. index, _ := presenceIndex(mi.Desc, fd)
  460. fieldNumber := fd.Number()
  461. elemType := fs.Type.Elem()
  462. return fieldInfo{
  463. fieldDesc: fd,
  464. has: func(p pointer) bool {
  465. if p.IsNil() {
  466. return false
  467. }
  468. return mi.present(p, index)
  469. },
  470. clear: func(p pointer) {
  471. mi.clearPresent(p, index)
  472. p.Apply(fieldOffset).AtomicSetNilPointer()
  473. },
  474. get: func(p pointer) protoreflect.Value {
  475. if p.IsNil() || !mi.present(p, index) {
  476. return conv.Zero()
  477. }
  478. fp := p.Apply(fieldOffset)
  479. mp := fp.AtomicGetPointer()
  480. if mp.IsNil() {
  481. // Lazily unmarshal this field.
  482. mi.lazyUnmarshal(p, fieldNumber)
  483. mp = fp.AtomicGetPointer()
  484. }
  485. rv := mp.AsValueOf(elemType)
  486. return conv.PBValueOf(rv)
  487. },
  488. set: func(p pointer, v protoreflect.Value) {
  489. val := pointerOfValue(conv.GoValueOf(v))
  490. if val.IsNil() {
  491. panic("invalid nil pointer")
  492. }
  493. p.Apply(fieldOffset).AtomicSetPointer(val)
  494. mi.setPresent(p, index)
  495. },
  496. mutable: func(p pointer) protoreflect.Value {
  497. fp := p.Apply(fieldOffset)
  498. mp := fp.AtomicGetPointer()
  499. if mp.IsNil() {
  500. if mi.present(p, index) {
  501. // Lazily unmarshal this field.
  502. mi.lazyUnmarshal(p, fieldNumber)
  503. mp = fp.AtomicGetPointer()
  504. } else {
  505. mp = pointerOfValue(conv.GoValueOf(conv.New()))
  506. fp.AtomicSetPointer(mp)
  507. mi.setPresent(p, index)
  508. }
  509. }
  510. return conv.PBValueOf(mp.AsValueOf(fs.Type.Elem()))
  511. },
  512. newMessage: func() protoreflect.Message {
  513. return conv.New().Message()
  514. },
  515. newField: func() protoreflect.Value {
  516. return conv.New()
  517. },
  518. }
  519. }
  520. // A presenceList wraps a List, updating presence bits as necessary when the
  521. // list contents change.
  522. type presenceList struct {
  523. pvalueList
  524. setPresence func(bool)
  525. }
  526. type pvalueList interface {
  527. protoreflect.List
  528. //Unwrapper
  529. }
  530. func (list presenceList) Append(v protoreflect.Value) {
  531. list.pvalueList.Append(v)
  532. list.setPresence(true)
  533. }
  534. func (list presenceList) Truncate(i int) {
  535. list.pvalueList.Truncate(i)
  536. list.setPresence(i > 0)
  537. }
  538. // presenceIndex returns the index to pass to presence functions.
  539. //
  540. // TODO: field.Desc.Index() would be simpler, and would give space to record the presence of oneof fields.
  541. func presenceIndex(md protoreflect.MessageDescriptor, fd protoreflect.FieldDescriptor) (uint32, presenceSize) {
  542. found := false
  543. var index, numIndices uint32
  544. for i := 0; i < md.Fields().Len(); i++ {
  545. f := md.Fields().Get(i)
  546. if f == fd {
  547. found = true
  548. index = numIndices
  549. }
  550. if f.ContainingOneof() == nil || isLastOneofField(f) {
  551. numIndices++
  552. }
  553. }
  554. if !found {
  555. panic(fmt.Sprintf("BUG: %v not in %v", fd.Name(), md.FullName()))
  556. }
  557. return index, presenceSize(numIndices)
  558. }
  559. func isLastOneofField(fd protoreflect.FieldDescriptor) bool {
  560. fields := fd.ContainingOneof().Fields()
  561. return fields.Get(fields.Len()-1) == fd
  562. }
  563. func (mi *MessageInfo) setPresent(p pointer, index uint32) {
  564. p.Apply(mi.presenceOffset).PresenceInfo().SetPresent(index, mi.presenceSize)
  565. }
  566. func (mi *MessageInfo) clearPresent(p pointer, index uint32) {
  567. p.Apply(mi.presenceOffset).PresenceInfo().ClearPresent(index)
  568. }
  569. func (mi *MessageInfo) present(p pointer, index uint32) bool {
  570. return p.Apply(mi.presenceOffset).PresenceInfo().Present(index)
  571. }
  572. // usePresenceForField implements the somewhat intricate logic of when
  573. // the presence bitmap is used for a field. The main logic is that a
  574. // field that is optional or that can be lazy will use the presence
  575. // bit, but for proto2, also maps have a presence bit. It also records
  576. // if the field can ever be lazy, which is true if we have a
  577. // lazyOffset and the field is a message or a slice of messages. A
  578. // field that is lazy will always need a presence bit. Oneofs are not
  579. // lazy and do not use presence, unless they are a synthetic oneof,
  580. // which is a proto3 optional field. For proto3 optionals, we use the
  581. // presence and they can also be lazy when applicable (a message).
  582. func usePresenceForField(si opaqueStructInfo, fd protoreflect.FieldDescriptor) (usePresence, canBeLazy bool) {
  583. hasLazyField := fd.(interface{ IsLazy() bool }).IsLazy()
  584. // Non-oneof scalar fields with explicit field presence use the presence array.
  585. usesPresenceArray := fd.HasPresence() && fd.Message() == nil && (fd.ContainingOneof() == nil || fd.ContainingOneof().IsSynthetic())
  586. switch {
  587. case fd.ContainingOneof() != nil && !fd.ContainingOneof().IsSynthetic():
  588. return false, false
  589. case fd.IsMap():
  590. return false, false
  591. case fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind:
  592. return hasLazyField, hasLazyField
  593. default:
  594. return usesPresenceArray || (hasLazyField && fd.HasPresence()), false
  595. }
  596. }