legacy_extension.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  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. "reflect"
  8. "sync"
  9. "google.golang.org/protobuf/internal/descfmt"
  10. ptag "google.golang.org/protobuf/internal/encoding/tag"
  11. "google.golang.org/protobuf/internal/filedesc"
  12. pvalue "google.golang.org/protobuf/internal/value"
  13. pref "google.golang.org/protobuf/reflect/protoreflect"
  14. preg "google.golang.org/protobuf/reflect/protoregistry"
  15. "google.golang.org/protobuf/reflect/prototype"
  16. piface "google.golang.org/protobuf/runtime/protoiface"
  17. )
  18. // legacyExtensionDescKey is a comparable version of protoiface.ExtensionDescV1
  19. // suitable for use as a key in a map.
  20. type legacyExtensionDescKey struct {
  21. typeV2 pref.ExtensionType
  22. extendedType reflect.Type
  23. extensionType reflect.Type
  24. field int32
  25. name string
  26. tag string
  27. filename string
  28. }
  29. func legacyExtensionDescKeyOf(d *piface.ExtensionDescV1) legacyExtensionDescKey {
  30. return legacyExtensionDescKey{
  31. d.Type,
  32. reflect.TypeOf(d.ExtendedType),
  33. reflect.TypeOf(d.ExtensionType),
  34. d.Field, d.Name, d.Tag, d.Filename,
  35. }
  36. }
  37. var (
  38. legacyExtensionTypeCache sync.Map // map[legacyExtensionDescKey]protoreflect.ExtensionType
  39. legacyExtensionDescCache sync.Map // map[protoreflect.ExtensionType]*protoiface.ExtensionDescV1
  40. )
  41. // legacyExtensionDescFromType converts a v2 protoreflect.ExtensionType to a
  42. // protoiface.ExtensionDescV1. The returned ExtensionDesc must not be mutated.
  43. func legacyExtensionDescFromType(xt pref.ExtensionType) *piface.ExtensionDescV1 {
  44. // Fast-path: check whether an extension desc is already nested within.
  45. if xt, ok := xt.(interface {
  46. ProtoLegacyExtensionDesc() *piface.ExtensionDescV1
  47. }); ok {
  48. if d := xt.ProtoLegacyExtensionDesc(); d != nil {
  49. return d
  50. }
  51. }
  52. // Fast-path: check the cache for whether this ExtensionType has already
  53. // been converted to a legacy descriptor.
  54. if d, ok := legacyExtensionDescCache.Load(xt); ok {
  55. return d.(*piface.ExtensionDescV1)
  56. }
  57. // Determine the parent type if possible.
  58. var parent piface.MessageV1
  59. messageName := xt.Descriptor().ContainingMessage().FullName()
  60. if mt, _ := preg.GlobalTypes.FindMessageByName(messageName); mt != nil {
  61. // Create a new parent message and unwrap it if possible.
  62. mv := mt.New().Interface()
  63. t := reflect.TypeOf(mv)
  64. if mv, ok := mv.(pvalue.Unwrapper); ok {
  65. t = reflect.TypeOf(mv.ProtoUnwrap())
  66. }
  67. // Check whether the message implements the legacy v1 Message interface.
  68. mz := reflect.Zero(t).Interface()
  69. if mz, ok := mz.(piface.MessageV1); ok {
  70. parent = mz
  71. }
  72. }
  73. // Determine the v1 extension type, which is unfortunately not the same as
  74. // the v2 ExtensionType.GoType.
  75. extType := xt.GoType()
  76. switch extType.Kind() {
  77. case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
  78. extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
  79. case reflect.Ptr:
  80. if extType.Elem().Kind() == reflect.Slice {
  81. extType = extType.Elem() // *[]T -> []T for repeated fields
  82. }
  83. }
  84. // Reconstruct the legacy enum full name, which is an odd mixture of the
  85. // proto package name with the Go type name.
  86. var enumName string
  87. if xt.Descriptor().Kind() == pref.EnumKind {
  88. // Derive Go type name.
  89. t := extType
  90. if t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice {
  91. t = t.Elem()
  92. }
  93. enumName = t.Name()
  94. // Derive the proto package name.
  95. // For legacy enums, obtain the proto package from the raw descriptor.
  96. var protoPkg string
  97. if fd := xt.Descriptor().Enum().ParentFile(); fd != nil {
  98. protoPkg = string(fd.Package())
  99. }
  100. if ed, ok := reflect.Zero(t).Interface().(enumV1); ok && protoPkg == "" {
  101. b, _ := ed.EnumDescriptor()
  102. protoPkg = string(legacyLoadFileDesc(b).Package())
  103. }
  104. if protoPkg != "" {
  105. enumName = protoPkg + "." + enumName
  106. }
  107. }
  108. // Derive the proto file that the extension was declared within.
  109. var filename string
  110. if fd := xt.Descriptor().ParentFile(); fd != nil {
  111. filename = fd.Path()
  112. }
  113. // Construct and return a ExtensionDescV1.
  114. d := &piface.ExtensionDescV1{
  115. Type: xt,
  116. ExtendedType: parent,
  117. ExtensionType: reflect.Zero(extType).Interface(),
  118. Field: int32(xt.Descriptor().Number()),
  119. Name: string(xt.Descriptor().FullName()),
  120. Tag: ptag.Marshal(xt.Descriptor(), enumName),
  121. Filename: filename,
  122. }
  123. if d, ok := legacyExtensionDescCache.LoadOrStore(xt, d); ok {
  124. return d.(*piface.ExtensionDescV1)
  125. }
  126. return d
  127. }
  128. // legacyExtensionTypeFromDesc converts a protoiface.ExtensionDescV1 to a
  129. // v2 protoreflect.ExtensionType. The returned descriptor type takes ownership
  130. // of the input extension desc. The input must not be mutated so long as the
  131. // returned type is still in use.
  132. func legacyExtensionTypeFromDesc(d *piface.ExtensionDescV1) pref.ExtensionType {
  133. // Fast-path: check whether an extension type is already nested within.
  134. if d.Type != nil {
  135. return d.Type
  136. }
  137. // Fast-path: check the cache for whether this ExtensionType has already
  138. // been converted from a legacy descriptor.
  139. dk := legacyExtensionDescKeyOf(d)
  140. if t, ok := legacyExtensionTypeCache.Load(dk); ok {
  141. return t.(pref.ExtensionType)
  142. }
  143. // Resolve enum or message dependencies.
  144. var ed pref.EnumDescriptor
  145. var md pref.MessageDescriptor
  146. t := reflect.TypeOf(d.ExtensionType)
  147. isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
  148. isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
  149. if isOptional || isRepeated {
  150. t = t.Elem()
  151. }
  152. switch v := reflect.Zero(t).Interface().(type) {
  153. case pref.Enum:
  154. ed = v.Descriptor()
  155. case enumV1:
  156. ed = LegacyLoadEnumDesc(t)
  157. case pref.ProtoMessage:
  158. md = v.ProtoReflect().Descriptor()
  159. case messageV1:
  160. md = LegacyLoadMessageDesc(t)
  161. }
  162. // Derive basic field information from the struct tag.
  163. var evs pref.EnumValueDescriptors
  164. if ed != nil {
  165. evs = ed.Values()
  166. }
  167. fd := ptag.Unmarshal(d.Tag, t, evs).(*filedesc.Field)
  168. // Construct a v2 ExtensionType.
  169. xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
  170. xd.L0.ParentFile = filedesc.SurrogateProto2
  171. xd.L0.FullName = pref.FullName(d.Name)
  172. xd.L1.Number = pref.FieldNumber(d.Field)
  173. xd.L2.Cardinality = fd.L1.Cardinality
  174. xd.L1.Kind = fd.L1.Kind
  175. xd.L2.IsPacked = fd.L1.IsPacked
  176. xd.L2.Default = fd.L1.Default
  177. xd.L1.Extendee = Export{}.MessageDescriptorOf(d.ExtendedType)
  178. xd.L2.Enum = ed
  179. xd.L2.Message = md
  180. xt := LegacyExtensionTypeOf(xd, t)
  181. // Cache the conversion for both directions.
  182. legacyExtensionDescCache.LoadOrStore(xt, d)
  183. if xt, ok := legacyExtensionTypeCache.LoadOrStore(dk, xt); ok {
  184. return xt.(pref.ExtensionType)
  185. }
  186. return xt
  187. }
  188. // LegacyExtensionTypeOf returns a protoreflect.ExtensionType where the
  189. // element type of the field is t. The type t must be provided if the field
  190. // is an enum or message.
  191. //
  192. // This is exported for testing purposes.
  193. func LegacyExtensionTypeOf(xd pref.ExtensionDescriptor, t reflect.Type) pref.ExtensionType {
  194. var conv pvalue.Converter
  195. var isLegacy bool
  196. xt := &prototype.Extension{ExtensionDescriptor: xd}
  197. switch xd.Kind() {
  198. case pref.EnumKind:
  199. conv, isLegacy = newConverter(t, xd.Kind())
  200. xt.NewEnum = conv.NewEnum
  201. case pref.MessageKind, pref.GroupKind:
  202. conv, isLegacy = newConverter(t, xd.Kind())
  203. xt.NewMessage = conv.NewMessage
  204. default:
  205. // Extension types for non-enums and non-messages are simple.
  206. return &prototype.Extension{ExtensionDescriptor: xd}
  207. }
  208. if !isLegacy {
  209. return xt
  210. }
  211. // Wrap ExtensionType such that GoType presents the legacy Go type.
  212. xt2 := &legacyExtensionType{ExtensionType: xt}
  213. if xd.Cardinality() != pref.Repeated {
  214. xt2.typ = t
  215. xt2.new = func() pref.Value {
  216. return xt.New()
  217. }
  218. xt2.valueOf = func(v interface{}) pref.Value {
  219. if reflect.TypeOf(v) != xt2.typ {
  220. panic(fmt.Sprintf("invalid type: got %T, want %v", v, xt2.typ))
  221. }
  222. if xd.Kind() == pref.EnumKind {
  223. return xt.ValueOf(Export{}.EnumOf(v))
  224. } else {
  225. return xt.ValueOf(Export{}.MessageOf(v).Interface())
  226. }
  227. }
  228. xt2.interfaceOf = func(v pref.Value) interface{} {
  229. return xt.InterfaceOf(v).(pvalue.Unwrapper).ProtoUnwrap()
  230. }
  231. } else {
  232. xt2.typ = reflect.PtrTo(reflect.SliceOf(t))
  233. xt2.new = func() pref.Value {
  234. v := reflect.New(xt2.typ.Elem()).Interface()
  235. return pref.ValueOf(pvalue.ListOf(v, conv))
  236. }
  237. xt2.valueOf = func(v interface{}) pref.Value {
  238. if reflect.TypeOf(v) != xt2.typ {
  239. panic(fmt.Sprintf("invalid type: got %T, want %v", v, xt2.typ))
  240. }
  241. return pref.ValueOf(pvalue.ListOf(v, conv))
  242. }
  243. xt2.interfaceOf = func(pv pref.Value) interface{} {
  244. v := pv.List().(pvalue.Unwrapper).ProtoUnwrap()
  245. if reflect.TypeOf(v) != xt2.typ {
  246. panic(fmt.Sprintf("invalid type: got %T, want %v", v, xt2.typ))
  247. }
  248. return v
  249. }
  250. }
  251. return xt2
  252. }
  253. type legacyExtensionType struct {
  254. pref.ExtensionType
  255. typ reflect.Type
  256. new func() pref.Value
  257. valueOf func(interface{}) pref.Value
  258. interfaceOf func(pref.Value) interface{}
  259. }
  260. func (x *legacyExtensionType) GoType() reflect.Type { return x.typ }
  261. func (x *legacyExtensionType) New() pref.Value { return x.new() }
  262. func (x *legacyExtensionType) ValueOf(v interface{}) pref.Value { return x.valueOf(v) }
  263. func (x *legacyExtensionType) InterfaceOf(v pref.Value) interface{} { return x.interfaceOf(v) }
  264. func (x *legacyExtensionType) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, x.Descriptor()) }