legacy_extension.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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. "google.golang.org/protobuf/internal/encoding/messageset"
  9. ptag "google.golang.org/protobuf/internal/encoding/tag"
  10. "google.golang.org/protobuf/internal/filedesc"
  11. pref "google.golang.org/protobuf/reflect/protoreflect"
  12. preg "google.golang.org/protobuf/reflect/protoregistry"
  13. piface "google.golang.org/protobuf/runtime/protoiface"
  14. )
  15. var legacyExtensionInfoCache sync.Map // map[protoreflect.ExtensionType]*ExtensionInfo
  16. // legacyExtensionDescFromType converts a protoreflect.ExtensionType to an
  17. // ExtensionInfo. The returned ExtensionInfo must not be mutated.
  18. func legacyExtensionDescFromType(xt pref.ExtensionType) *ExtensionInfo {
  19. // Fast-path: check whether this is an ExtensionInfo.
  20. if xt, ok := xt.(*ExtensionInfo); ok {
  21. return xt
  22. }
  23. // Fast-path: check the cache for whether this ExtensionType has already
  24. // been converted to an ExtensionInfo.
  25. if d, ok := legacyExtensionInfoCache.Load(xt); ok {
  26. return d.(*ExtensionInfo)
  27. }
  28. tt := xt.GoType()
  29. if xt.TypeDescriptor().Cardinality() == pref.Repeated {
  30. tt = tt.Elem().Elem()
  31. }
  32. xi := &ExtensionInfo{}
  33. InitExtensionInfo(xi, xt.TypeDescriptor().Descriptor(), tt)
  34. xi.lazyInit() // populate legacy fields
  35. if xi, ok := legacyExtensionInfoCache.LoadOrStore(xt, xi); ok {
  36. return xi.(*ExtensionInfo)
  37. }
  38. return xi
  39. }
  40. func (xi *ExtensionInfo) initToLegacy() {
  41. xd := xi.desc
  42. var parent piface.MessageV1
  43. messageName := xd.ContainingMessage().FullName()
  44. if mt, _ := preg.GlobalTypes.FindMessageByName(messageName); mt != nil {
  45. // Create a new parent message and unwrap it if possible.
  46. mv := mt.New().Interface()
  47. t := reflect.TypeOf(mv)
  48. if mv, ok := mv.(Unwrapper); ok {
  49. t = reflect.TypeOf(mv.ProtoUnwrap())
  50. }
  51. // Check whether the message implements the legacy v1 Message interface.
  52. mz := reflect.Zero(t).Interface()
  53. if mz, ok := mz.(piface.MessageV1); ok {
  54. parent = mz
  55. }
  56. }
  57. // Determine the v1 extension type, which is unfortunately not the same as
  58. // the v2 ExtensionType.GoType.
  59. extType := xi.goType
  60. switch extType.Kind() {
  61. case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
  62. extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
  63. }
  64. // Reconstruct the legacy enum full name.
  65. var enumName string
  66. if xd.Kind() == pref.EnumKind {
  67. enumName = legacyEnumName(xd.Enum())
  68. }
  69. // Derive the proto file that the extension was declared within.
  70. var filename string
  71. if fd := xd.ParentFile(); fd != nil {
  72. filename = fd.Path()
  73. }
  74. // For MessageSet extensions, the name used is the parent message.
  75. name := xd.FullName()
  76. if messageset.IsMessageSetExtension(xd) {
  77. name = name.Parent()
  78. }
  79. xi.ExtendedType = parent
  80. xi.ExtensionType = reflect.Zero(extType).Interface()
  81. xi.Field = int32(xd.Number())
  82. xi.Name = string(name)
  83. xi.Tag = ptag.Marshal(xd, enumName)
  84. xi.Filename = filename
  85. }
  86. // initFromLegacy initializes an ExtensionInfo from
  87. // the contents of the deprecated exported fields of the type.
  88. func (xi *ExtensionInfo) initFromLegacy() {
  89. // Resolve enum or message dependencies.
  90. var ed pref.EnumDescriptor
  91. var md pref.MessageDescriptor
  92. t := reflect.TypeOf(xi.ExtensionType)
  93. isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
  94. isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
  95. if isOptional || isRepeated {
  96. t = t.Elem()
  97. }
  98. switch v := reflect.Zero(t).Interface().(type) {
  99. case pref.Enum:
  100. ed = v.Descriptor()
  101. case enumV1:
  102. ed = LegacyLoadEnumDesc(t)
  103. case pref.ProtoMessage:
  104. md = v.ProtoReflect().Descriptor()
  105. case messageV1:
  106. md = LegacyLoadMessageDesc(t)
  107. }
  108. // Derive basic field information from the struct tag.
  109. var evs pref.EnumValueDescriptors
  110. if ed != nil {
  111. evs = ed.Values()
  112. }
  113. fd := ptag.Unmarshal(xi.Tag, t, evs).(*filedesc.Field)
  114. // Construct a v2 ExtensionType.
  115. xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
  116. xd.L0.ParentFile = filedesc.SurrogateProto2
  117. xd.L0.FullName = pref.FullName(xi.Name)
  118. xd.L1.Number = pref.FieldNumber(xi.Field)
  119. xd.L2.Cardinality = fd.L1.Cardinality
  120. xd.L1.Kind = fd.L1.Kind
  121. xd.L2.IsPacked = fd.L1.IsPacked
  122. xd.L2.Default = fd.L1.Default
  123. xd.L1.Extendee = Export{}.MessageDescriptorOf(xi.ExtendedType)
  124. xd.L2.Enum = ed
  125. xd.L2.Message = md
  126. // Derive real extension field name for MessageSets.
  127. if messageset.IsMessageSet(xd.L1.Extendee) && md.FullName() == xd.L0.FullName {
  128. xd.L0.FullName = xd.L0.FullName.Append(messageset.ExtensionName)
  129. }
  130. tt := reflect.TypeOf(xi.ExtensionType)
  131. if isOptional {
  132. tt = tt.Elem()
  133. }
  134. xi.desc = xd
  135. xi.goType = tt
  136. }