176 lines
7.5 KiB
Go
176 lines
7.5 KiB
Go
// 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"
|
|
|
|
"google.golang.org/protobuf/internal/descopts"
|
|
"google.golang.org/protobuf/internal/encoding/messageset"
|
|
ptag "google.golang.org/protobuf/internal/encoding/tag"
|
|
"google.golang.org/protobuf/internal/filedesc"
|
|
"google.golang.org/protobuf/internal/pragma"
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
"google.golang.org/protobuf/reflect/protoregistry"
|
|
"google.golang.org/protobuf/runtime/protoiface"
|
|
)
|
|
|
|
func (xi *ExtensionInfo) initToLegacy() {
|
|
xd := xi.desc
|
|
var parent protoiface.MessageV1
|
|
messageName := xd.ContainingMessage().FullName()
|
|
if mt, _ := protoregistry.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.(protoiface.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() == protoreflect.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() {
|
|
// The v1 API returns "type incomplete" descriptors where only the
|
|
// field number is specified. In such a case, use a placeholder.
|
|
if xi.ExtendedType == nil || xi.ExtensionType == nil {
|
|
xd := placeholderExtension{
|
|
name: protoreflect.FullName(xi.Name),
|
|
number: protoreflect.FieldNumber(xi.Field),
|
|
}
|
|
xi.desc = extensionTypeDescriptor{xd, xi}
|
|
return
|
|
}
|
|
|
|
// Resolve enum or message dependencies.
|
|
var ed protoreflect.EnumDescriptor
|
|
var md protoreflect.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 protoreflect.Enum:
|
|
ed = v.Descriptor()
|
|
case enumV1:
|
|
ed = LegacyLoadEnumDesc(t)
|
|
case protoreflect.ProtoMessage:
|
|
md = v.ProtoReflect().Descriptor()
|
|
case messageV1:
|
|
md = LegacyLoadMessageDesc(t)
|
|
}
|
|
|
|
// Derive basic field information from the struct tag.
|
|
var evs protoreflect.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 = protoreflect.FullName(xi.Name)
|
|
xd.L1.Number = protoreflect.FieldNumber(xi.Field)
|
|
xd.L1.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.goType = tt
|
|
xi.desc = extensionTypeDescriptor{xd, xi}
|
|
}
|
|
|
|
type placeholderExtension struct {
|
|
name protoreflect.FullName
|
|
number protoreflect.FieldNumber
|
|
}
|
|
|
|
func (x placeholderExtension) ParentFile() protoreflect.FileDescriptor { return nil }
|
|
func (x placeholderExtension) Parent() protoreflect.Descriptor { return nil }
|
|
func (x placeholderExtension) Index() int { return 0 }
|
|
func (x placeholderExtension) Syntax() protoreflect.Syntax { return 0 }
|
|
func (x placeholderExtension) Name() protoreflect.Name { return x.name.Name() }
|
|
func (x placeholderExtension) FullName() protoreflect.FullName { return x.name }
|
|
func (x placeholderExtension) IsPlaceholder() bool { return true }
|
|
func (x placeholderExtension) Options() protoreflect.ProtoMessage { return descopts.Field }
|
|
func (x placeholderExtension) Number() protoreflect.FieldNumber { return x.number }
|
|
func (x placeholderExtension) Cardinality() protoreflect.Cardinality { return 0 }
|
|
func (x placeholderExtension) Kind() protoreflect.Kind { return 0 }
|
|
func (x placeholderExtension) HasJSONName() bool { return false }
|
|
func (x placeholderExtension) JSONName() string { return "[" + string(x.name) + "]" }
|
|
func (x placeholderExtension) TextName() string { return "[" + string(x.name) + "]" }
|
|
func (x placeholderExtension) HasPresence() bool { return false }
|
|
func (x placeholderExtension) HasOptionalKeyword() bool { return false }
|
|
func (x placeholderExtension) IsExtension() bool { return true }
|
|
func (x placeholderExtension) IsWeak() bool { return false }
|
|
func (x placeholderExtension) IsPacked() bool { return false }
|
|
func (x placeholderExtension) IsList() bool { return false }
|
|
func (x placeholderExtension) IsMap() bool { return false }
|
|
func (x placeholderExtension) MapKey() protoreflect.FieldDescriptor { return nil }
|
|
func (x placeholderExtension) MapValue() protoreflect.FieldDescriptor { return nil }
|
|
func (x placeholderExtension) HasDefault() bool { return false }
|
|
func (x placeholderExtension) Default() protoreflect.Value { return protoreflect.Value{} }
|
|
func (x placeholderExtension) DefaultEnumValue() protoreflect.EnumValueDescriptor { return nil }
|
|
func (x placeholderExtension) ContainingOneof() protoreflect.OneofDescriptor { return nil }
|
|
func (x placeholderExtension) ContainingMessage() protoreflect.MessageDescriptor { return nil }
|
|
func (x placeholderExtension) Enum() protoreflect.EnumDescriptor { return nil }
|
|
func (x placeholderExtension) Message() protoreflect.MessageDescriptor { return nil }
|
|
func (x placeholderExtension) ProtoType(protoreflect.FieldDescriptor) { return }
|
|
func (x placeholderExtension) ProtoInternal(pragma.DoNotImplement) { return }
|