| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- // Copyright 2018 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package impl
- import (
- "reflect"
- "sync"
- "google.golang.org/protobuf/internal/encoding/messageset"
- ptag "google.golang.org/protobuf/internal/encoding/tag"
- "google.golang.org/protobuf/internal/filedesc"
- pref "google.golang.org/protobuf/reflect/protoreflect"
- preg "google.golang.org/protobuf/reflect/protoregistry"
- piface "google.golang.org/protobuf/runtime/protoiface"
- )
- var legacyExtensionInfoCache sync.Map // map[protoreflect.ExtensionType]*ExtensionInfo
- // legacyExtensionDescFromType converts a protoreflect.ExtensionType to an
- // ExtensionInfo. The returned ExtensionInfo must not be mutated.
- func legacyExtensionDescFromType(xt pref.ExtensionType) *ExtensionInfo {
- // Fast-path: check whether this is an ExtensionInfo.
- if xt, ok := xt.(*ExtensionInfo); ok {
- return xt
- }
- // Fast-path: check the cache for whether this ExtensionType has already
- // been converted to an ExtensionInfo.
- if d, ok := legacyExtensionInfoCache.Load(xt); ok {
- return d.(*ExtensionInfo)
- }
- tt := xt.GoType()
- if xt.TypeDescriptor().Cardinality() == pref.Repeated {
- tt = tt.Elem().Elem()
- }
- xi := &ExtensionInfo{}
- InitExtensionInfo(xi, xt.TypeDescriptor().Descriptor(), tt)
- xi.lazyInit() // populate legacy fields
- if xi, ok := legacyExtensionInfoCache.LoadOrStore(xt, xi); ok {
- return xi.(*ExtensionInfo)
- }
- return xi
- }
- func (xi *ExtensionInfo) initToLegacy() {
- xd := xi.desc
- var parent piface.MessageV1
- messageName := xd.ContainingMessage().FullName()
- if mt, _ := preg.GlobalTypes.FindMessageByName(messageName); mt != nil {
- // Create a new parent message and unwrap it if possible.
- mv := mt.New().Interface()
- t := reflect.TypeOf(mv)
- if mv, ok := mv.(Unwrapper); ok {
- t = reflect.TypeOf(mv.ProtoUnwrap())
- }
- // Check whether the message implements the legacy v1 Message interface.
- mz := reflect.Zero(t).Interface()
- if mz, ok := mz.(piface.MessageV1); ok {
- parent = mz
- }
- }
- // Determine the v1 extension type, which is unfortunately not the same as
- // the v2 ExtensionType.GoType.
- extType := xi.goType
- switch extType.Kind() {
- case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
- extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
- }
- // Reconstruct the legacy enum full name.
- var enumName string
- if xd.Kind() == pref.EnumKind {
- enumName = legacyEnumName(xd.Enum())
- }
- // Derive the proto file that the extension was declared within.
- var filename string
- if fd := xd.ParentFile(); fd != nil {
- filename = fd.Path()
- }
- // For MessageSet extensions, the name used is the parent message.
- name := xd.FullName()
- if messageset.IsMessageSetExtension(xd) {
- name = name.Parent()
- }
- xi.ExtendedType = parent
- xi.ExtensionType = reflect.Zero(extType).Interface()
- xi.Field = int32(xd.Number())
- xi.Name = string(name)
- xi.Tag = ptag.Marshal(xd, enumName)
- xi.Filename = filename
- }
- // initFromLegacy initializes an ExtensionInfo from
- // the contents of the deprecated exported fields of the type.
- func (xi *ExtensionInfo) initFromLegacy() {
- // Resolve enum or message dependencies.
- var ed pref.EnumDescriptor
- var md pref.MessageDescriptor
- t := reflect.TypeOf(xi.ExtensionType)
- isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
- isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
- if isOptional || isRepeated {
- t = t.Elem()
- }
- switch v := reflect.Zero(t).Interface().(type) {
- case pref.Enum:
- ed = v.Descriptor()
- case enumV1:
- ed = LegacyLoadEnumDesc(t)
- case pref.ProtoMessage:
- md = v.ProtoReflect().Descriptor()
- case messageV1:
- md = LegacyLoadMessageDesc(t)
- }
- // Derive basic field information from the struct tag.
- var evs pref.EnumValueDescriptors
- if ed != nil {
- evs = ed.Values()
- }
- fd := ptag.Unmarshal(xi.Tag, t, evs).(*filedesc.Field)
- // Construct a v2 ExtensionType.
- xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
- xd.L0.ParentFile = filedesc.SurrogateProto2
- xd.L0.FullName = pref.FullName(xi.Name)
- xd.L1.Number = pref.FieldNumber(xi.Field)
- xd.L2.Cardinality = fd.L1.Cardinality
- xd.L1.Kind = fd.L1.Kind
- xd.L2.IsPacked = fd.L1.IsPacked
- xd.L2.Default = fd.L1.Default
- xd.L1.Extendee = Export{}.MessageDescriptorOf(xi.ExtendedType)
- xd.L2.Enum = ed
- xd.L2.Message = md
- // Derive real extension field name for MessageSets.
- if messageset.IsMessageSet(xd.L1.Extendee) && md.FullName() == xd.L0.FullName {
- xd.L0.FullName = xd.L0.FullName.Append(messageset.ExtensionName)
- }
- tt := reflect.TypeOf(xi.ExtensionType)
- if isOptional {
- tt = tt.Elem()
- }
- xi.desc = xd
- xi.goType = tt
- }
|