legacy_extension_hack.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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. "reflect"
  7. "sync"
  8. "unsafe"
  9. protoV1 "github.com/golang/protobuf/proto"
  10. pref "github.com/golang/protobuf/v2/reflect/protoreflect"
  11. )
  12. // TODO: The logic in the file is a hack and should be in the v1 repository.
  13. // We need to break the dependency on proto v1 since it is v1 that will
  14. // eventually need to depend on v2.
  15. // TODO: The v1 API currently exposes no exported functionality for interacting
  16. // with the extension data structures. We will need to make changes in v1 so
  17. // that v2 can access these data structures without relying on unsafe.
  18. var (
  19. extTypeA = reflect.TypeOf(map[int32]protoV1.Extension(nil))
  20. extTypeB = reflect.TypeOf(protoV1.XXX_InternalExtensions{})
  21. )
  22. type legacyExtensionIface interface {
  23. Len() int
  24. Has(pref.FieldNumber) bool
  25. Get(pref.FieldNumber) legacyExtensionEntry
  26. Set(pref.FieldNumber, legacyExtensionEntry)
  27. Clear(pref.FieldNumber)
  28. Range(f func(pref.FieldNumber, legacyExtensionEntry) bool)
  29. }
  30. func makeLegacyExtensionMapFunc(t reflect.Type) func(*messageDataType) legacyExtensionIface {
  31. fx1, _ := t.FieldByName("XXX_extensions")
  32. fx2, _ := t.FieldByName("XXX_InternalExtensions")
  33. switch {
  34. case fx1.Type == extTypeA:
  35. return func(p *messageDataType) legacyExtensionIface {
  36. rv := p.p.asType(t).Elem()
  37. return (*legacyExtensionMap)(unsafe.Pointer(rv.UnsafeAddr() + fx1.Offset))
  38. }
  39. case fx2.Type == extTypeB:
  40. return func(p *messageDataType) legacyExtensionIface {
  41. rv := p.p.asType(t).Elem()
  42. return (*legacyExtensionSyncMap)(unsafe.Pointer(rv.UnsafeAddr() + fx2.Offset))
  43. }
  44. default:
  45. return nil
  46. }
  47. }
  48. // TODO: We currently don't do locking with legacyExtensionSyncMap.p.mu.
  49. // The locking behavior was already obscure "feature" beforehand,
  50. // and it is not obvious how it translates to the v2 API.
  51. // The v2 API presents a Range method, which calls a user provided function,
  52. // which may in turn call other methods on the map. In such a use case,
  53. // acquiring a lock within each method would result in a reentrant deadlock.
  54. // legacyExtensionSyncMap is identical to protoV1.XXX_InternalExtensions.
  55. // It implements legacyExtensionIface.
  56. type legacyExtensionSyncMap struct {
  57. p *struct {
  58. mu sync.Mutex
  59. m legacyExtensionMap
  60. }
  61. }
  62. func (m legacyExtensionSyncMap) Len() int {
  63. if m.p == nil {
  64. return 0
  65. }
  66. return m.p.m.Len()
  67. }
  68. func (m legacyExtensionSyncMap) Has(n pref.FieldNumber) bool {
  69. return m.p.m.Has(n)
  70. }
  71. func (m legacyExtensionSyncMap) Get(n pref.FieldNumber) legacyExtensionEntry {
  72. if m.p == nil {
  73. return legacyExtensionEntry{}
  74. }
  75. return m.p.m.Get(n)
  76. }
  77. func (m *legacyExtensionSyncMap) Set(n pref.FieldNumber, x legacyExtensionEntry) {
  78. if m.p == nil {
  79. m.p = new(struct {
  80. mu sync.Mutex
  81. m legacyExtensionMap
  82. })
  83. }
  84. m.p.m.Set(n, x)
  85. }
  86. func (m legacyExtensionSyncMap) Clear(n pref.FieldNumber) {
  87. m.p.m.Clear(n)
  88. }
  89. func (m legacyExtensionSyncMap) Range(f func(pref.FieldNumber, legacyExtensionEntry) bool) {
  90. if m.p == nil {
  91. return
  92. }
  93. m.p.m.Range(f)
  94. }
  95. // legacyExtensionMap is identical to map[int32]protoV1.Extension.
  96. // It implements legacyExtensionIface.
  97. type legacyExtensionMap map[pref.FieldNumber]legacyExtensionEntry
  98. func (m legacyExtensionMap) Len() int {
  99. return len(m)
  100. }
  101. func (m legacyExtensionMap) Has(n pref.FieldNumber) bool {
  102. _, ok := m[n]
  103. return ok
  104. }
  105. func (m legacyExtensionMap) Get(n pref.FieldNumber) legacyExtensionEntry {
  106. return m[n]
  107. }
  108. func (m *legacyExtensionMap) Set(n pref.FieldNumber, x legacyExtensionEntry) {
  109. if *m == nil {
  110. *m = make(map[pref.FieldNumber]legacyExtensionEntry)
  111. }
  112. (*m)[n] = x
  113. }
  114. func (m *legacyExtensionMap) Clear(n pref.FieldNumber) {
  115. delete(*m, n)
  116. }
  117. func (m legacyExtensionMap) Range(f func(pref.FieldNumber, legacyExtensionEntry) bool) {
  118. for n, x := range m {
  119. if !f(n, x) {
  120. return
  121. }
  122. }
  123. }
  124. // legacyExtensionEntry is identical to protoV1.Extension.
  125. type legacyExtensionEntry struct {
  126. desc *protoV1.ExtensionDesc
  127. val interface{}
  128. raw []byte
  129. }