protobuf-go/internal/impl/legacy_extension.go

177 lines
7.5 KiB
Go
Raw Normal View History

// 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"
)
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
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.
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
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()
}
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
xi.ExtendedType = parent
xi.ExtensionType = reflect.Zero(extType).Interface()
xi.Field = int32(xd.Number())
xi.Name = string(name)
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
xi.Tag = ptag.Marshal(xd, enumName)
xi.Filename = filename
}
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
// 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
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
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()
}
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
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
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
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)
}
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
tt := reflect.TypeOf(xi.ExtensionType)
if isOptional {
tt = tt.Elem()
}
all: unify protoV1.ExtensionDesc and proto.ExtensionType Change protoV1.ExtensionDesc to directly implement ExtensionType rather than delegating to one. Unify the previous types protoiface.ExtensionDescV1 and filetype.Extension in impl.ExtensionInfo. The protoV1.ExtensionDesc type becomes an alias to ExtensionInfo. This gives us: - Just one implementation of ExtensionType. - Generated foopb.E_Ext vars are canonical ExtensionTypes. - Generated foopb.E_Ext vars are also v1.ExtensionDescs for backwards compatibility. - Conversion between legacy and modern representations happens transparently when lazily initializing an ExtensionInfo. Overall, a simplification for users of generated code, since they can mostly ignore the ExtensionDesc/ExtentionType distinction and use the same value in either the old or new API. This is change 3/5 in a series of commits changing protoV1.ExtensionDesc to directly implement protoreflect.ExtensionType. 1. [v2] Add protoimpl.ExtensionInfo as an alias for protoiface.ExtensionDescV1. 2. [v1] Update references to protoimpl.ExtensionInfo to use protoiface.ExtensionInfo. 3. [v2] Create protoimpl.ExtensionInfo (an alias to a new type in the impl package) and remove protoiface.ExtensionDescV1. 4. [v1] Remove unneeded explicit conversions between ExtensionDesc and ExtensionType (since the former now directly implements the latter). 5. [v2] Remove stub conversion functions. Change-Id: I96ee890541ec11b2412e1a72c9d7b96e4d7f66b4 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189563 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-08-08 22:45:59 +00:00
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 }