mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-17 01:12:51 +00:00
reflect/prototype: initial commit
Add the prototype package which provides constructors for protoreflect.{Enum,Message,Extension}Type. Switch all usages of the internal/prototype equivalent to the new package. Switch all custom implementions of {Enum,Message}Type to the new package. Change-Id: Ia9dae6fed4f2b90e55c123627044a7faf098c4b1 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/178438 Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
parent
4fe9663f4c
commit
b2f66bedb4
@ -101,6 +101,8 @@ func (file *fileDesc) resolveMessages() {
|
||||
}
|
||||
|
||||
func (file *fileDesc) resolveExtensions() {
|
||||
// TODO: Delete this and use reflect/prototype instead.
|
||||
|
||||
for i := range file.allExtensions {
|
||||
xd := &file.allExtensions[i]
|
||||
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/prototype"
|
||||
)
|
||||
|
||||
// Export is a zero-length named type that exists only to export a set of
|
||||
@ -31,24 +32,16 @@ func (Export) EnumOf(e enum) pref.Enum {
|
||||
// EnumTypeOf returns the protoreflect.EnumType for e.
|
||||
func (Export) EnumTypeOf(e enum) pref.EnumType {
|
||||
if ev, ok := e.(pref.Enum); ok {
|
||||
return &enumType{ev.Descriptor(), reflect.TypeOf(e)}
|
||||
return &prototype.Enum{
|
||||
EnumDescriptor: ev.Descriptor(),
|
||||
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
||||
return reflect.ValueOf(n).Convert(reflect.TypeOf(e)).Interface().(pref.Enum)
|
||||
},
|
||||
}
|
||||
}
|
||||
return legacyWrapper.EnumTypeOf(e)
|
||||
}
|
||||
|
||||
// TODO: This needs to be centralized in a package.
|
||||
type enumType struct {
|
||||
// TODO: Remove me as an embedded field.
|
||||
pref.EnumDescriptor
|
||||
typ reflect.Type // must implement protoreflect.Enum
|
||||
}
|
||||
|
||||
func (t *enumType) Descriptor() pref.EnumDescriptor { return t.EnumDescriptor }
|
||||
func (t *enumType) GoType() reflect.Type { return t.typ }
|
||||
func (t *enumType) New(n pref.EnumNumber) pref.Enum {
|
||||
return reflect.ValueOf(n).Convert(t.typ).Interface().(pref.Enum)
|
||||
}
|
||||
|
||||
// EnumDescriptorOf returns the protoreflect.EnumDescriptor for e.
|
||||
func (Export) EnumDescriptorOf(e enum) pref.EnumDescriptor {
|
||||
if ev, ok := e.(pref.Enum); ok {
|
||||
@ -82,24 +75,16 @@ func (Export) MessageOf(m message) pref.Message {
|
||||
// MessageTypeOf returns the protoreflect.MessageType for m.
|
||||
func (Export) MessageTypeOf(m message) pref.MessageType {
|
||||
if mv, ok := m.(pref.ProtoMessage); ok {
|
||||
return &messageType{mv.ProtoReflect().Descriptor(), reflect.TypeOf(m)}
|
||||
return &prototype.Message{
|
||||
MessageDescriptor: mv.ProtoReflect().Descriptor(),
|
||||
NewMessage: func() pref.Message {
|
||||
return reflect.New(reflect.TypeOf(m).Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
|
||||
},
|
||||
}
|
||||
}
|
||||
return legacyWrapper.MessageTypeOf(m)
|
||||
}
|
||||
|
||||
// TODO: This needs to be centralized in a package.
|
||||
type messageType struct {
|
||||
// TODO: Remove me as an embedded field.
|
||||
pref.MessageDescriptor
|
||||
typ reflect.Type // must implement protoreflect.ProtoMessage
|
||||
}
|
||||
|
||||
func (t *messageType) Descriptor() pref.MessageDescriptor { return t.MessageDescriptor }
|
||||
func (t *messageType) GoType() reflect.Type { return t.typ }
|
||||
func (t *messageType) New() pref.Message {
|
||||
return reflect.New(t.typ.Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
|
||||
}
|
||||
|
||||
// MessageDescriptorOf returns the protoreflect.MessageDescriptor for m.
|
||||
func (Export) MessageDescriptorOf(m message) pref.MessageDescriptor {
|
||||
if mv, ok := m.(pref.ProtoMessage); ok {
|
||||
|
@ -4,14 +4,39 @@
|
||||
|
||||
package impl
|
||||
|
||||
import pvalue "google.golang.org/protobuf/internal/value"
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
piface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
// TODO: Add a default LegacyWrapper that panics with a more helpful message?
|
||||
var legacyWrapper pvalue.LegacyWrapper
|
||||
var legacyWrapper LegacyWrapper
|
||||
|
||||
// RegisterLegacyWrapper registers a set of constructor functions that are
|
||||
// called when a legacy enum or message is encountered that does not natively
|
||||
// support the protobuf reflection APIs.
|
||||
func RegisterLegacyWrapper(w pvalue.LegacyWrapper) {
|
||||
func RegisterLegacyWrapper(w LegacyWrapper) {
|
||||
legacyWrapper = w
|
||||
}
|
||||
|
||||
// LegacyWrapper is a set of wrapper methods that wraps legacy v1 Go types
|
||||
// to implement the v2 reflection APIs.
|
||||
type LegacyWrapper interface {
|
||||
NewConverter(reflect.Type, pref.Kind) pvalue.Converter
|
||||
|
||||
EnumOf(interface{}) pref.Enum
|
||||
EnumTypeOf(interface{}) pref.EnumType
|
||||
EnumDescriptorOf(interface{}) pref.EnumDescriptor
|
||||
|
||||
MessageOf(interface{}) pref.Message
|
||||
MessageTypeOf(interface{}) pref.MessageType
|
||||
MessageDescriptorOf(interface{}) pref.MessageDescriptor
|
||||
|
||||
// TODO: Remove these eventually.
|
||||
// See the TODOs in internal/impl/legacy_extension.go.
|
||||
ExtensionDescFromType(pref.ExtensionType) *piface.ExtensionDescV1
|
||||
ExtensionTypeFromDesc(*piface.ExtensionDescV1) pref.ExtensionType
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot refle
|
||||
if !reflect.PtrTo(ot).Implements(ft) {
|
||||
panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
|
||||
}
|
||||
conv := pvalue.NewLegacyConverter(ot.Field(0).Type, fd.Kind(), legacyWrapper)
|
||||
conv := newConverter(ot.Field(0).Type, fd.Kind())
|
||||
fieldOffset := offsetOf(fs)
|
||||
// TODO: Implement unsafe fast path?
|
||||
return fieldInfo{
|
||||
@ -86,12 +86,9 @@ func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot refle
|
||||
}
|
||||
rv.Set(reflect.Zero(rv.Type()))
|
||||
},
|
||||
newMessage: func() pref.Message {
|
||||
// This is only valid for messages and panics for other kinds.
|
||||
return conv.MessageType.New()
|
||||
},
|
||||
offset: fieldOffset,
|
||||
isPointer: true,
|
||||
newMessage: conv.NewMessage,
|
||||
offset: fieldOffset,
|
||||
isPointer: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,8 +97,8 @@ func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo
|
||||
if ft.Kind() != reflect.Map {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
|
||||
}
|
||||
keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.MapKey().Kind(), legacyWrapper)
|
||||
valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.MapValue().Kind(), legacyWrapper)
|
||||
keyConv := newConverter(ft.Key(), fd.MapKey().Kind())
|
||||
valConv := newConverter(ft.Elem(), fd.MapValue().Kind())
|
||||
wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
|
||||
fieldOffset := offsetOf(fs)
|
||||
// TODO: Implement unsafe fast path?
|
||||
@ -142,7 +139,7 @@ func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo
|
||||
if ft.Kind() != reflect.Slice {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
|
||||
}
|
||||
conv := pvalue.NewLegacyConverter(ft.Elem(), fd.Kind(), legacyWrapper)
|
||||
conv := newConverter(ft.Elem(), fd.Kind())
|
||||
var wiretag uint64
|
||||
if !fd.IsPacked() {
|
||||
wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
|
||||
@ -197,7 +194,7 @@ func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldIn
|
||||
ft = ft.Elem()
|
||||
}
|
||||
}
|
||||
conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
|
||||
conv := newConverter(ft, fd.Kind())
|
||||
fieldOffset := offsetOf(fs)
|
||||
wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
|
||||
// TODO: Implement unsafe fast path?
|
||||
@ -267,7 +264,7 @@ func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldIn
|
||||
|
||||
func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
|
||||
ft := fs.Type
|
||||
conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
|
||||
conv := newConverter(ft, fd.Kind())
|
||||
fieldOffset := offsetOf(fs)
|
||||
// TODO: Implement unsafe fast path?
|
||||
wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
|
||||
@ -300,14 +297,12 @@ func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField) fieldI
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
rv.Set(reflect.Zero(rv.Type()))
|
||||
},
|
||||
newMessage: func() pref.Message {
|
||||
return conv.MessageType.New()
|
||||
},
|
||||
funcs: fieldCoder(fd, ft),
|
||||
offset: fieldOffset,
|
||||
isPointer: true,
|
||||
wiretag: wiretag,
|
||||
tagsize: wire.SizeVarint(wiretag),
|
||||
newMessage: conv.NewMessage,
|
||||
funcs: fieldCoder(fd, ft),
|
||||
offset: fieldOffset,
|
||||
isPointer: true,
|
||||
wiretag: wiretag,
|
||||
tagsize: wire.SizeVarint(wiretag),
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,3 +337,10 @@ func makeOneofInfo(od pref.OneofDescriptor, fs reflect.StructField, wrappersByTy
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newConverter(t reflect.Type, k pref.Kind) pvalue.Converter {
|
||||
if legacyWrapper != nil {
|
||||
return legacyWrapper.NewConverter(t, k)
|
||||
}
|
||||
return pvalue.NewConverter(t, k)
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
scalar "google.golang.org/protobuf/internal/scalar"
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/prototype"
|
||||
|
||||
proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
|
||||
"google.golang.org/protobuf/types/descriptorpb"
|
||||
@ -189,8 +190,8 @@ type (
|
||||
MapBytes map[MyString]MyBytes
|
||||
)
|
||||
|
||||
var scalarProto2Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto2)), PBType: ptype.GoMessage(
|
||||
mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
var scalarProto2Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto2)), PBType: &prototype.Message{
|
||||
MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto2,
|
||||
FullName: "ScalarProto2",
|
||||
Fields: []ptype.Field{
|
||||
@ -219,10 +220,10 @@ var scalarProto2Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto2
|
||||
{Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind, Default: V([]byte("22"))},
|
||||
},
|
||||
}),
|
||||
func(pref.MessageType) pref.Message {
|
||||
NewMessage: func() pref.Message {
|
||||
return new(ScalarProto2)
|
||||
},
|
||||
)}
|
||||
}}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (m *ScalarProto2) Type() pref.MessageType { return scalarProto2Type.PBType }
|
||||
@ -304,8 +305,8 @@ type ScalarProto3 struct {
|
||||
MyBytesA MyString `protobuf:"22"`
|
||||
}
|
||||
|
||||
var scalarProto3Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto3)), PBType: ptype.GoMessage(
|
||||
mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
var scalarProto3Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto3)), PBType: &prototype.Message{
|
||||
MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto3,
|
||||
FullName: "ScalarProto3",
|
||||
Fields: []ptype.Field{
|
||||
@ -334,10 +335,10 @@ var scalarProto3Type = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ScalarProto3
|
||||
{Name: "f22", Number: 22, Cardinality: pref.Optional, Kind: pref.BytesKind},
|
||||
},
|
||||
}),
|
||||
func(pref.MessageType) pref.Message {
|
||||
NewMessage: func() pref.Message {
|
||||
return new(ScalarProto3)
|
||||
},
|
||||
)}
|
||||
}}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (m *ScalarProto3) Type() pref.MessageType { return scalarProto3Type.PBType }
|
||||
@ -437,8 +438,8 @@ type ListScalars struct {
|
||||
MyBytes4 ListStrings `protobuf:"19"`
|
||||
}
|
||||
|
||||
var listScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ListScalars)), PBType: ptype.GoMessage(
|
||||
mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
var listScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ListScalars)), PBType: &prototype.Message{
|
||||
MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto2,
|
||||
FullName: "ListScalars",
|
||||
Fields: []ptype.Field{
|
||||
@ -465,10 +466,10 @@ var listScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(ListScalars))
|
||||
{Name: "f19", Number: 19, Cardinality: pref.Repeated, Kind: pref.BytesKind},
|
||||
},
|
||||
}),
|
||||
func(pref.MessageType) pref.Message {
|
||||
NewMessage: func() pref.Message {
|
||||
return new(ListScalars)
|
||||
},
|
||||
)}
|
||||
}}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (m *ListScalars) Type() pref.MessageType { return listScalarsType.PBType }
|
||||
@ -628,8 +629,8 @@ func mustMakeMapEntry(n pref.FieldNumber, keyKind, valKind pref.Kind) ptype.Fiel
|
||||
}
|
||||
}
|
||||
|
||||
var mapScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(MapScalars)), PBType: ptype.GoMessage(
|
||||
mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
var mapScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(MapScalars)), PBType: &prototype.Message{
|
||||
MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto2,
|
||||
FullName: "MapScalars",
|
||||
Fields: []ptype.Field{
|
||||
@ -663,10 +664,10 @@ var mapScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(MapScalars)),
|
||||
mustMakeMapEntry(25, pref.StringKind, pref.BytesKind),
|
||||
},
|
||||
}),
|
||||
func(pref.MessageType) pref.Message {
|
||||
NewMessage: func() pref.Message {
|
||||
return new(MapScalars)
|
||||
},
|
||||
)}
|
||||
}}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (m *MapScalars) Type() pref.MessageType { return mapScalarsType.PBType }
|
||||
@ -807,8 +808,8 @@ type OneofScalars struct {
|
||||
Union isOneofScalars_Union `protobuf_oneof:"union"`
|
||||
}
|
||||
|
||||
var oneofScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(OneofScalars)), PBType: ptype.GoMessage(
|
||||
mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
var oneofScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(OneofScalars)), PBType: &prototype.Message{
|
||||
MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto2,
|
||||
FullName: "OneofScalars",
|
||||
Fields: []ptype.Field{
|
||||
@ -828,10 +829,10 @@ var oneofScalarsType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(OneofScalars
|
||||
},
|
||||
Oneofs: []ptype.Oneof{{Name: "union"}},
|
||||
}),
|
||||
func(pref.MessageType) pref.Message {
|
||||
NewMessage: func() pref.Message {
|
||||
return new(OneofScalars)
|
||||
},
|
||||
)}
|
||||
}}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (m *OneofScalars) Type() pref.MessageType { return oneofScalarsType.PBType }
|
||||
@ -983,16 +984,16 @@ func TestOneofs(t *testing.T) {
|
||||
|
||||
type EnumProto2 int32
|
||||
|
||||
var enumProto2Type = ptype.GoEnum(
|
||||
mustMakeEnumDesc(ptype.StandaloneEnum{
|
||||
var enumProto2Type = &prototype.Enum{
|
||||
EnumDescriptor: mustMakeEnumDesc(ptype.StandaloneEnum{
|
||||
Syntax: pref.Proto2,
|
||||
FullName: "EnumProto2",
|
||||
Values: []ptype.EnumValue{{Name: "DEAD", Number: 0xdead}, {Name: "BEEF", Number: 0xbeef}},
|
||||
}),
|
||||
func(_ pref.EnumType, n pref.EnumNumber) pref.Enum {
|
||||
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
||||
return EnumProto2(n)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (e EnumProto2) Type() pref.EnumType { return enumProto2Type }
|
||||
@ -1002,16 +1003,16 @@ func (e EnumProto2) Number() pref.EnumNumber { return pref.EnumNumber(e)
|
||||
|
||||
type EnumProto3 int32
|
||||
|
||||
var enumProto3Type = ptype.GoEnum(
|
||||
mustMakeEnumDesc(ptype.StandaloneEnum{
|
||||
var enumProto3Type = &prototype.Enum{
|
||||
EnumDescriptor: mustMakeEnumDesc(ptype.StandaloneEnum{
|
||||
Syntax: pref.Proto3,
|
||||
FullName: "EnumProto3",
|
||||
Values: []ptype.EnumValue{{Name: "ALPHA", Number: 0}, {Name: "BRAVO", Number: 1}},
|
||||
}),
|
||||
func(_ pref.EnumType, n pref.EnumNumber) pref.Enum {
|
||||
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
||||
return EnumProto3(n)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Remove this.
|
||||
func (e EnumProto3) Type() pref.EnumType { return enumProto3Type }
|
||||
@ -1031,8 +1032,8 @@ type EnumMessages struct {
|
||||
Union isEnumMessages_Union `protobuf_oneof:"union"`
|
||||
}
|
||||
|
||||
var enumMessagesType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(EnumMessages)), PBType: ptype.GoMessage(
|
||||
mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
var enumMessagesType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(EnumMessages)), PBType: &prototype.Message{
|
||||
MessageDescriptor: mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto2,
|
||||
FullName: "EnumMessages",
|
||||
Fields: []ptype.Field{
|
||||
@ -1051,10 +1052,10 @@ var enumMessagesType = pimpl.MessageInfo{GoType: reflect.TypeOf(new(EnumMessages
|
||||
},
|
||||
Oneofs: []ptype.Oneof{{Name: "union"}},
|
||||
}),
|
||||
func(pref.MessageType) pref.Message {
|
||||
NewMessage: func() pref.Message {
|
||||
return new(EnumMessages)
|
||||
},
|
||||
)}
|
||||
}}
|
||||
|
||||
var enumMapDesc = mustMakeMessageDesc(ptype.StandaloneMessage{
|
||||
Syntax: pref.Proto2,
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
ptype "google.golang.org/protobuf/internal/prototype"
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/prototype"
|
||||
)
|
||||
|
||||
// wrapEnum wraps v as a protoreflect.Enum,
|
||||
@ -33,16 +34,20 @@ func loadEnumType(t reflect.Type) pref.EnumType {
|
||||
}
|
||||
|
||||
// Slow-path: derive enum descriptor and initialize EnumType.
|
||||
var et pref.EnumType
|
||||
var m sync.Map // map[protoreflect.EnumNumber]proto.Enum
|
||||
ed := LoadEnumDesc(t)
|
||||
et := ptype.GoEnum(ed, func(et pref.EnumType, n pref.EnumNumber) pref.Enum {
|
||||
if e, ok := m.Load(n); ok {
|
||||
return e.(pref.Enum)
|
||||
}
|
||||
e := &enumWrapper{num: n, pbTyp: et, goTyp: t}
|
||||
m.Store(n, e)
|
||||
return e
|
||||
})
|
||||
et = &prototype.Enum{
|
||||
EnumDescriptor: ed,
|
||||
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
||||
if e, ok := m.Load(n); ok {
|
||||
return e.(pref.Enum)
|
||||
}
|
||||
e := &enumWrapper{num: n, pbTyp: et, goTyp: t}
|
||||
m.Store(n, e)
|
||||
return e
|
||||
},
|
||||
}
|
||||
if et, ok := enumTypeCache.LoadOrStore(t, et); ok {
|
||||
return et.(pref.EnumType)
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package legacy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
pimpl "google.golang.org/protobuf/internal/impl"
|
||||
@ -17,8 +18,8 @@ import (
|
||||
// functions that we do not want to appear in godoc.
|
||||
type Export struct{}
|
||||
|
||||
func (Export) EnumOf(e interface{}) pvalue.LegacyEnum {
|
||||
return wrapEnum(reflect.ValueOf(e)).(pvalue.LegacyEnum)
|
||||
func (Export) EnumOf(e interface{}) pref.Enum {
|
||||
return wrapEnum(reflect.ValueOf(e))
|
||||
}
|
||||
|
||||
func (Export) EnumTypeOf(e interface{}) pref.EnumType {
|
||||
@ -29,8 +30,8 @@ func (Export) EnumDescriptorOf(e interface{}) pref.EnumDescriptor {
|
||||
return LoadEnumDesc(reflect.TypeOf(e))
|
||||
}
|
||||
|
||||
func (Export) MessageOf(m interface{}) pvalue.LegacyMessage {
|
||||
return wrapMessage(reflect.ValueOf(m)).ProtoReflect().(pvalue.LegacyMessage)
|
||||
func (Export) MessageOf(m interface{}) pref.Message {
|
||||
return wrapMessage(reflect.ValueOf(m)).ProtoReflect()
|
||||
}
|
||||
|
||||
func (Export) MessageTypeOf(m interface{}) pref.MessageType {
|
||||
@ -49,6 +50,61 @@ func (Export) ExtensionTypeFromDesc(d *piface.ExtensionDescV1) pref.ExtensionTyp
|
||||
return extensionTypeFromDesc(d)
|
||||
}
|
||||
|
||||
var (
|
||||
enumIfaceV2 = reflect.TypeOf((*pref.Enum)(nil)).Elem()
|
||||
messageIfaceV1 = reflect.TypeOf((*piface.MessageV1)(nil)).Elem()
|
||||
messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
|
||||
)
|
||||
|
||||
func (Export) NewConverter(t reflect.Type, k pref.Kind) pvalue.Converter {
|
||||
c, _ := newConverter(t, k)
|
||||
return c
|
||||
}
|
||||
|
||||
func newConverter(t reflect.Type, k pref.Kind) (pvalue.Converter, bool) {
|
||||
switch k {
|
||||
case pref.EnumKind:
|
||||
if t.Kind() == reflect.Int32 && !t.Implements(enumIfaceV2) {
|
||||
return pvalue.Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
||||
}
|
||||
return pref.ValueOf(pref.EnumNumber(v.Int()))
|
||||
},
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
return reflect.ValueOf(v.Enum()).Convert(t)
|
||||
},
|
||||
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
||||
return wrapEnum(reflect.ValueOf(n).Convert(t))
|
||||
},
|
||||
}, true
|
||||
}
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV1) && !t.Implements(messageIfaceV2) {
|
||||
return pvalue.Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
||||
}
|
||||
return pref.ValueOf(Export{}.MessageOf(v.Interface()))
|
||||
},
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(v.Message().(pvalue.Unwrapper).ProtoUnwrap())
|
||||
if rv.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), t))
|
||||
}
|
||||
return rv
|
||||
},
|
||||
NewMessage: func() pref.Message {
|
||||
return wrapMessage(reflect.New(t.Elem())).ProtoReflect()
|
||||
},
|
||||
}, true
|
||||
}
|
||||
}
|
||||
return pvalue.NewConverter(t, k), false
|
||||
}
|
||||
|
||||
func init() {
|
||||
pimpl.RegisterLegacyWrapper(Export{})
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
preg "google.golang.org/protobuf/reflect/protoregistry"
|
||||
"google.golang.org/protobuf/reflect/prototype"
|
||||
piface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
@ -171,12 +172,19 @@ func extensionTypeFromDesc(d *piface.ExtensionDescV1) pref.ExtensionType {
|
||||
// Construct a v2 ExtensionType.
|
||||
var ed pref.EnumDescriptor
|
||||
var md pref.MessageDescriptor
|
||||
conv := pvalue.NewLegacyConverter(t, f.Kind, Export{})
|
||||
if conv.EnumType != nil {
|
||||
ed = conv.EnumType.Descriptor()
|
||||
}
|
||||
if conv.MessageType != nil {
|
||||
md = conv.MessageType.Descriptor()
|
||||
switch f.Kind {
|
||||
case pref.EnumKind:
|
||||
if e, ok := reflect.Zero(t).Interface().(pref.Enum); ok {
|
||||
ed = e.Descriptor()
|
||||
} else {
|
||||
ed = LoadEnumDesc(t)
|
||||
}
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
if m, ok := reflect.Zero(t).Interface().(pref.ProtoMessage); ok {
|
||||
md = m.ProtoReflect().Descriptor()
|
||||
} else {
|
||||
md = LoadMessageDesc(t)
|
||||
}
|
||||
}
|
||||
xd, err := ptype.NewExtension(&ptype.StandaloneExtension{
|
||||
FullName: pref.FullName(d.Name),
|
||||
@ -207,17 +215,21 @@ func extensionTypeFromDesc(d *piface.ExtensionDescV1) pref.ExtensionType {
|
||||
//
|
||||
// This is exported for testing purposes.
|
||||
func ExtensionTypeOf(xd pref.ExtensionDescriptor, t reflect.Type) pref.ExtensionType {
|
||||
// Extension types for non-enums and non-messages are simple.
|
||||
var conv pvalue.Converter
|
||||
var isLegacy bool
|
||||
xt := &prototype.Extension{ExtensionDescriptor: xd}
|
||||
switch xd.Kind() {
|
||||
case pref.EnumKind, pref.MessageKind, pref.GroupKind:
|
||||
case pref.EnumKind:
|
||||
conv, isLegacy = newConverter(t, xd.Kind())
|
||||
xt.NewEnum = conv.NewEnum
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
conv, isLegacy = newConverter(t, xd.Kind())
|
||||
xt.NewMessage = conv.NewMessage
|
||||
default:
|
||||
return ptype.GoExtension(xd, nil, nil)
|
||||
// Extension types for non-enums and non-messages are simple.
|
||||
return &prototype.Extension{ExtensionDescriptor: xd}
|
||||
}
|
||||
|
||||
// Create an ExtensionType where GoType is the wrapper type.
|
||||
conv := pvalue.NewLegacyConverter(t, xd.Kind(), Export{})
|
||||
xt := ptype.GoExtension(xd, conv.EnumType, conv.MessageType)
|
||||
if !conv.IsLegacy {
|
||||
if !isLegacy {
|
||||
return xt
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
pimpl "google.golang.org/protobuf/internal/impl"
|
||||
ptype "google.golang.org/protobuf/internal/prototype"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/prototype"
|
||||
)
|
||||
|
||||
// wrapMessage wraps v as a protoreflect.ProtoMessage,
|
||||
@ -38,10 +39,12 @@ func loadMessageInfo(t reflect.Type) *pimpl.MessageInfo {
|
||||
md := LoadMessageDesc(t)
|
||||
mt := new(pimpl.MessageInfo)
|
||||
mt.GoType = t
|
||||
mt.PBType = ptype.GoMessage(md, func(pref.MessageType) pref.Message {
|
||||
p := reflect.New(t.Elem()).Interface()
|
||||
return mt.MessageOf(p)
|
||||
})
|
||||
mt.PBType = &prototype.Message{
|
||||
MessageDescriptor: md,
|
||||
NewMessage: func() pref.Message {
|
||||
return mt.MessageOf(reflect.New(t.Elem()).Interface())
|
||||
},
|
||||
}
|
||||
if mt, ok := messageTypeCache.LoadOrStore(t, mt); ok {
|
||||
return mt.(*pimpl.MessageInfo)
|
||||
}
|
||||
|
@ -1,305 +0,0 @@
|
||||
// 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 prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/descfmt"
|
||||
"google.golang.org/protobuf/internal/value"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// GoEnum creates a new protoreflect.EnumType by combining the provided
|
||||
// protoreflect.EnumDescriptor with the provided constructor function.
|
||||
func GoEnum(ed protoreflect.EnumDescriptor, fn func(protoreflect.EnumType, protoreflect.EnumNumber) protoreflect.Enum) protoreflect.EnumType {
|
||||
if ed.IsPlaceholder() {
|
||||
panic("enum descriptor must not be a placeholder")
|
||||
}
|
||||
return &goEnum{EnumDescriptor: ed, new: fn}
|
||||
}
|
||||
|
||||
type goEnum struct {
|
||||
protoreflect.EnumDescriptor
|
||||
new func(protoreflect.EnumType, protoreflect.EnumNumber) protoreflect.Enum
|
||||
|
||||
once sync.Once
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (t *goEnum) Descriptor() protoreflect.EnumDescriptor {
|
||||
return t.EnumDescriptor
|
||||
}
|
||||
func (t *goEnum) GoType() reflect.Type {
|
||||
t.New(0) // initialize t.typ
|
||||
return t.typ
|
||||
}
|
||||
func (t *goEnum) New(n protoreflect.EnumNumber) protoreflect.Enum {
|
||||
e := t.new(t, n)
|
||||
t.once.Do(func() { t.typ = reflect.TypeOf(e) })
|
||||
if t.typ != reflect.TypeOf(e) {
|
||||
panic(fmt.Sprintf("mismatching types for enum: got %T, want %v", e, t.typ))
|
||||
}
|
||||
return e
|
||||
}
|
||||
func (t *goEnum) Format(s fmt.State, r rune) {
|
||||
descfmt.FormatDesc(s, r, t)
|
||||
}
|
||||
|
||||
// GoMessage creates a new protoreflect.MessageType by combining the provided
|
||||
// protoreflect.MessageDescriptor with the provided constructor function.
|
||||
func GoMessage(md protoreflect.MessageDescriptor, fn func(protoreflect.MessageType) protoreflect.Message) protoreflect.MessageType {
|
||||
if md.IsPlaceholder() {
|
||||
panic("message descriptor must not be a placeholder")
|
||||
}
|
||||
// NOTE: Avoid calling fn in the constructor since fn itself may depend on
|
||||
// this function returning (for cyclic message dependencies).
|
||||
return &goMessage{MessageDescriptor: md, new: fn}
|
||||
}
|
||||
|
||||
type goMessage struct {
|
||||
protoreflect.MessageDescriptor
|
||||
new func(protoreflect.MessageType) protoreflect.Message
|
||||
|
||||
once sync.Once
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
func (t *goMessage) Descriptor() protoreflect.MessageDescriptor {
|
||||
return t.MessageDescriptor
|
||||
}
|
||||
func (t *goMessage) GoType() reflect.Type {
|
||||
t.New() // initialize t.typ
|
||||
return t.typ
|
||||
}
|
||||
func (t *goMessage) New() protoreflect.Message {
|
||||
m := t.new(t)
|
||||
mi := m.Interface()
|
||||
t.once.Do(func() { t.typ = reflect.TypeOf(mi) })
|
||||
if t.typ != reflect.TypeOf(mi) {
|
||||
panic(fmt.Sprintf("mismatching types for message: got %T, want %v", mi, t.typ))
|
||||
}
|
||||
return m
|
||||
}
|
||||
func (t *goMessage) Format(s fmt.State, r rune) {
|
||||
descfmt.FormatDesc(s, r, t)
|
||||
}
|
||||
|
||||
// GoExtension creates a new protoreflect.ExtensionType.
|
||||
//
|
||||
// An enum type must be provided for enum extension fields if
|
||||
// ExtensionDescriptor.EnumType does not implement protoreflect.EnumType,
|
||||
// in which case it replaces the original enum in ExtensionDescriptor.
|
||||
//
|
||||
// Similarly, a message type must be provided for message extension fields if
|
||||
// ExtensionDescriptor.MessageType does not implement protoreflect.MessageType,
|
||||
// in which case it replaces the original message in ExtensionDescriptor.
|
||||
//
|
||||
// The Go type is currently determined automatically.
|
||||
// The type is T for scalars and *[]T for lists (maps are not allowed).
|
||||
// The type T is determined as follows:
|
||||
//
|
||||
// +------------+-------------------------------------+
|
||||
// | Go type | Protobuf kind |
|
||||
// +------------+-------------------------------------+
|
||||
// | bool | BoolKind |
|
||||
// | int32 | Int32Kind, Sint32Kind, Sfixed32Kind |
|
||||
// | int64 | Int64Kind, Sint64Kind, Sfixed64Kind |
|
||||
// | uint32 | Uint32Kind, Fixed32Kind |
|
||||
// | uint64 | Uint64Kind, Fixed64Kind |
|
||||
// | float32 | FloatKind |
|
||||
// | float64 | DoubleKind |
|
||||
// | string | StringKind |
|
||||
// | []byte | BytesKind |
|
||||
// | E | EnumKind |
|
||||
// | M | MessageKind, GroupKind |
|
||||
// +------------+-------------------------------------+
|
||||
//
|
||||
// The type E is the concrete enum type returned by NewEnum,
|
||||
// which is often, but not required to be, a named int32 type.
|
||||
// The type M is the concrete message type returned by NewMessage,
|
||||
// which is often, but not required to be, a pointer to a named struct type.
|
||||
func GoExtension(xd protoreflect.ExtensionDescriptor, et protoreflect.EnumType, mt protoreflect.MessageType) protoreflect.ExtensionType {
|
||||
if !xd.IsExtension() {
|
||||
panic("field descriptor does not extend a message")
|
||||
}
|
||||
switch xd.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
if et2, ok := xd.Enum().(protoreflect.EnumType); ok && et == nil {
|
||||
et = et2
|
||||
}
|
||||
if et == nil {
|
||||
panic("enum type not provided for enum kind")
|
||||
}
|
||||
if mt != nil {
|
||||
panic("message type provided for enum kind")
|
||||
}
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
if mt2, ok := xd.Message().(protoreflect.MessageType); ok && mt == nil {
|
||||
mt = mt2
|
||||
}
|
||||
if et != nil {
|
||||
panic("enum type provided for message kind")
|
||||
}
|
||||
if mt == nil {
|
||||
panic("message type not provided for message kind")
|
||||
}
|
||||
default:
|
||||
if et != nil || mt != nil {
|
||||
panic(fmt.Sprintf("enum or message type provided for %v kind", xd.Kind()))
|
||||
}
|
||||
}
|
||||
return &goExtension{ExtensionDescriptor: xd, enumType: et, messageType: mt}
|
||||
}
|
||||
|
||||
type goExtension struct {
|
||||
protoreflect.ExtensionDescriptor
|
||||
enumType protoreflect.EnumType
|
||||
messageType protoreflect.MessageType
|
||||
|
||||
once sync.Once
|
||||
typ reflect.Type
|
||||
new func() protoreflect.Value
|
||||
valueOf func(v interface{}) protoreflect.Value
|
||||
interfaceOf func(v protoreflect.Value) interface{}
|
||||
}
|
||||
|
||||
func (t *goExtension) Descriptor() protoreflect.ExtensionDescriptor {
|
||||
return t.ExtensionDescriptor
|
||||
}
|
||||
func (t *goExtension) EnumType() protoreflect.EnumDescriptor {
|
||||
if t.enumType == nil {
|
||||
return nil
|
||||
}
|
||||
return t.enumType.Descriptor()
|
||||
}
|
||||
func (t *goExtension) MessageType() protoreflect.MessageDescriptor {
|
||||
if t.messageType == nil {
|
||||
return nil
|
||||
}
|
||||
return t.messageType.Descriptor()
|
||||
}
|
||||
func (t *goExtension) GoType() reflect.Type {
|
||||
t.lazyInit()
|
||||
return t.typ
|
||||
}
|
||||
func (t *goExtension) New() protoreflect.Value {
|
||||
t.lazyInit()
|
||||
pv := t.new()
|
||||
v := t.interfaceOf(pv)
|
||||
if reflect.TypeOf(v) != t.typ {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.typ))
|
||||
}
|
||||
return pv
|
||||
}
|
||||
func (t *goExtension) ValueOf(v interface{}) protoreflect.Value {
|
||||
t.lazyInit()
|
||||
if reflect.TypeOf(v) != t.typ {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.typ))
|
||||
}
|
||||
return t.valueOf(v)
|
||||
}
|
||||
func (t *goExtension) InterfaceOf(pv protoreflect.Value) interface{} {
|
||||
t.lazyInit()
|
||||
v := t.interfaceOf(pv)
|
||||
if reflect.TypeOf(v) != t.typ {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.typ))
|
||||
}
|
||||
return v
|
||||
}
|
||||
func (t *goExtension) Format(s fmt.State, r rune) {
|
||||
descfmt.FormatDesc(s, r, t)
|
||||
}
|
||||
func (t *goExtension) lazyInit() {
|
||||
t.once.Do(func() {
|
||||
switch t.Cardinality() {
|
||||
case protoreflect.Optional:
|
||||
switch t.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
t.typ = t.enumType.GoType()
|
||||
t.new = func() protoreflect.Value {
|
||||
return t.Default()
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
ev := v.(protoreflect.Enum)
|
||||
return protoreflect.ValueOf(ev.Number())
|
||||
}
|
||||
t.interfaceOf = func(pv protoreflect.Value) interface{} {
|
||||
return t.enumType.New(pv.Enum())
|
||||
}
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
t.typ = t.messageType.GoType()
|
||||
t.new = func() protoreflect.Value {
|
||||
return protoreflect.ValueOf(t.messageType.New())
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
mv := v.(protoreflect.ProtoMessage).ProtoReflect()
|
||||
return protoreflect.ValueOf(mv)
|
||||
}
|
||||
t.interfaceOf = func(pv protoreflect.Value) interface{} {
|
||||
return pv.Message().Interface()
|
||||
}
|
||||
default:
|
||||
t.typ = goTypeForPBKind[t.Kind()]
|
||||
t.new = func() protoreflect.Value {
|
||||
return t.Default()
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
return protoreflect.ValueOf(v)
|
||||
}
|
||||
t.interfaceOf = func(pv protoreflect.Value) interface{} {
|
||||
return pv.Interface()
|
||||
}
|
||||
}
|
||||
case protoreflect.Repeated:
|
||||
var typ reflect.Type
|
||||
var c value.Converter
|
||||
switch t.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
typ = t.enumType.GoType()
|
||||
c = value.NewEnumConverter(t.enumType)
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
typ = t.messageType.GoType()
|
||||
c = value.NewMessageConverter(t.messageType)
|
||||
default:
|
||||
typ = goTypeForPBKind[t.Kind()]
|
||||
c = value.NewConverter(typ, t.Kind())
|
||||
}
|
||||
t.typ = reflect.PtrTo(reflect.SliceOf(typ))
|
||||
t.new = func() protoreflect.Value {
|
||||
v := reflect.New(t.typ.Elem()).Interface()
|
||||
return protoreflect.ValueOf(value.ListOf(v, c))
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
return protoreflect.ValueOf(value.ListOf(v, c))
|
||||
}
|
||||
t.interfaceOf = func(pv protoreflect.Value) interface{} {
|
||||
return pv.List().(value.Unwrapper).ProtoUnwrap()
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid cardinality: %v", t.Cardinality()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var goTypeForPBKind = map[protoreflect.Kind]reflect.Type{
|
||||
protoreflect.BoolKind: reflect.TypeOf(bool(false)),
|
||||
protoreflect.Int32Kind: reflect.TypeOf(int32(0)),
|
||||
protoreflect.Sint32Kind: reflect.TypeOf(int32(0)),
|
||||
protoreflect.Sfixed32Kind: reflect.TypeOf(int32(0)),
|
||||
protoreflect.Int64Kind: reflect.TypeOf(int64(0)),
|
||||
protoreflect.Sint64Kind: reflect.TypeOf(int64(0)),
|
||||
protoreflect.Sfixed64Kind: reflect.TypeOf(int64(0)),
|
||||
protoreflect.Uint32Kind: reflect.TypeOf(uint32(0)),
|
||||
protoreflect.Fixed32Kind: reflect.TypeOf(uint32(0)),
|
||||
protoreflect.Uint64Kind: reflect.TypeOf(uint64(0)),
|
||||
protoreflect.Fixed64Kind: reflect.TypeOf(uint64(0)),
|
||||
protoreflect.FloatKind: reflect.TypeOf(float32(0)),
|
||||
protoreflect.DoubleKind: reflect.TypeOf(float64(0)),
|
||||
protoreflect.StringKind: reflect.TypeOf(string("")),
|
||||
protoreflect.BytesKind: reflect.TypeOf([]byte(nil)),
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
package prototype_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/protobuf/internal/prototype"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
|
||||
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
||||
)
|
||||
|
||||
func TestGoEnum(t *testing.T) {
|
||||
enumDescs := []protoreflect.EnumDescriptor{
|
||||
testpb.ForeignEnum(0).Descriptor(),
|
||||
testpb.TestAllTypes_NestedEnum(0).Descriptor(),
|
||||
}
|
||||
for _, ed := range enumDescs {
|
||||
et := prototype.GoEnum(ed, newEnum)
|
||||
if gotED := et.Descriptor(); gotED != ed {
|
||||
fmt.Errorf("GoEnum(ed (%v), newEnum).Descriptor() != ed", ed.FullName())
|
||||
}
|
||||
e := et.New(0)
|
||||
if gotED := e.Descriptor(); gotED != ed {
|
||||
fmt.Errorf("GoEnum(ed (%v), newEnum).New(0).Descriptor() != ed", ed.FullName())
|
||||
}
|
||||
if n := e.Number(); n != 0 {
|
||||
fmt.Errorf("GoEnum(ed (%v), newEnum).New(0).Number() = %v; want 0", ed.FullName(), n)
|
||||
}
|
||||
if _, ok := e.(fakeEnum); !ok {
|
||||
fmt.Errorf("GoEnum(ed (%v), newEnum).New(0) type is %T; want fakeEnum", ed.FullName(), e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoMessage(t *testing.T) {
|
||||
msgDescs := []protoreflect.MessageDescriptor{
|
||||
((*testpb.TestAllTypes)(nil)).ProtoReflect().Descriptor(),
|
||||
((*testpb.TestAllTypes_NestedMessage)(nil)).ProtoReflect().Descriptor(),
|
||||
}
|
||||
for _, md := range msgDescs {
|
||||
mt := prototype.GoMessage(md, newMessage)
|
||||
if gotMD := mt.Descriptor(); gotMD != md {
|
||||
fmt.Errorf("GoMessage(md (%v), newMessage).Descriptor() != md", md.FullName())
|
||||
}
|
||||
m := mt.New()
|
||||
if gotMD := m.Descriptor(); gotMD != md {
|
||||
fmt.Errorf("GoMessage(md (%v), newMessage).New().Descriptor() != md", md.FullName())
|
||||
}
|
||||
if _, ok := m.(*fakeMessage); !ok {
|
||||
fmt.Errorf("GoMessage(md (%v), newMessage).New() type is %T; want *fakeMessage", md.FullName(), m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoExtension(t *testing.T) {
|
||||
testCases := []struct {
|
||||
extName protoreflect.FullName
|
||||
wantNewType reflect.Type
|
||||
}{{
|
||||
extName: "goproto.proto.test.optional_int32_extension",
|
||||
wantNewType: reflect.TypeOf(int32(0)),
|
||||
}, {
|
||||
extName: "goproto.proto.test.optional_string_extension",
|
||||
wantNewType: reflect.TypeOf(""),
|
||||
}, {
|
||||
extName: "goproto.proto.test.repeated_int32_extension",
|
||||
wantNewType: reflect.TypeOf((*[]int32)(nil)),
|
||||
}, {
|
||||
extName: "goproto.proto.test.repeated_string_extension",
|
||||
wantNewType: reflect.TypeOf((*[]string)(nil)),
|
||||
}, {
|
||||
extName: "goproto.proto.test.repeated_string_extension",
|
||||
wantNewType: reflect.TypeOf((*[]string)(nil)),
|
||||
}, {
|
||||
extName: "goproto.proto.test.optional_nested_enum_extension",
|
||||
wantNewType: reflect.TypeOf((*fakeEnum)(nil)).Elem(),
|
||||
}, {
|
||||
extName: "goproto.proto.test.optional_nested_message_extension",
|
||||
wantNewType: reflect.TypeOf((*fakeMessageImpl)(nil)),
|
||||
}, {
|
||||
extName: "goproto.proto.test.repeated_nested_enum_extension",
|
||||
wantNewType: reflect.TypeOf((*[]fakeEnum)(nil)),
|
||||
}, {
|
||||
extName: "goproto.proto.test.repeated_nested_message_extension",
|
||||
wantNewType: reflect.TypeOf((*[]*fakeMessageImpl)(nil)),
|
||||
}}
|
||||
for _, tc := range testCases {
|
||||
xd, err := protoregistry.GlobalFiles.FindExtensionByName(tc.extName)
|
||||
if err != nil {
|
||||
t.Errorf("GlobalFiles.FindExtensionByName(%q) = _, %v; want _, <nil>", tc.extName, err)
|
||||
continue
|
||||
}
|
||||
var et protoreflect.EnumType
|
||||
if ed := xd.Enum(); ed != nil {
|
||||
et = prototype.GoEnum(ed, newEnum)
|
||||
}
|
||||
var mt protoreflect.MessageType
|
||||
if md := xd.Message(); md != nil {
|
||||
mt = prototype.GoMessage(md, newMessage)
|
||||
}
|
||||
xt := prototype.GoExtension(xd, et, mt)
|
||||
v := xt.InterfaceOf(xt.New())
|
||||
if typ := reflect.TypeOf(v); typ != tc.wantNewType {
|
||||
t.Errorf("GoExtension(xd (%v), et, mt).New() type unwraps to %v; want %v", tc.extName, typ, tc.wantNewType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type fakeMessage struct {
|
||||
imp *fakeMessageImpl
|
||||
protoreflect.Message
|
||||
}
|
||||
|
||||
func (m *fakeMessage) Type() protoreflect.MessageType { return m.imp.typ }
|
||||
func (m *fakeMessage) Descriptor() protoreflect.MessageDescriptor { return m.imp.typ.Descriptor() }
|
||||
func (m *fakeMessage) Interface() protoreflect.ProtoMessage { return m.imp }
|
||||
|
||||
type fakeMessageImpl struct{ typ protoreflect.MessageType }
|
||||
|
||||
func (m *fakeMessageImpl) ProtoReflect() protoreflect.Message { return &fakeMessage{imp: m} }
|
||||
|
||||
func newMessage(typ protoreflect.MessageType) protoreflect.Message {
|
||||
return (&fakeMessageImpl{typ: typ}).ProtoReflect()
|
||||
}
|
||||
|
||||
type fakeEnum struct {
|
||||
typ protoreflect.EnumType
|
||||
num protoreflect.EnumNumber
|
||||
}
|
||||
|
||||
func (e fakeEnum) Descriptor() protoreflect.EnumDescriptor { return e.typ.Descriptor() }
|
||||
func (e fakeEnum) Type() protoreflect.EnumType { return e.typ }
|
||||
func (e fakeEnum) Number() protoreflect.EnumNumber { return e.num }
|
||||
|
||||
func newEnum(typ protoreflect.EnumType, num protoreflect.EnumNumber) protoreflect.Enum {
|
||||
return fakeEnum{
|
||||
typ: typ,
|
||||
num: num,
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@ import (
|
||||
"reflect"
|
||||
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
piface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
// Unwrapper unwraps the value to the underlying value.
|
||||
@ -32,103 +31,60 @@ var (
|
||||
bytesType = reflect.TypeOf([]byte(nil))
|
||||
|
||||
enumIfaceV2 = reflect.TypeOf((*pref.Enum)(nil)).Elem()
|
||||
messageIfaceV1 = reflect.TypeOf((*piface.MessageV1)(nil)).Elem()
|
||||
messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
|
||||
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
)
|
||||
|
||||
// NewConverter matches a Go type with a protobuf kind and returns a Converter
|
||||
// that converts between the two. NewConverter panics if it unable to provide a
|
||||
// conversion between the two. The Converter methods also panic when they are
|
||||
// called on incorrect Go types.
|
||||
// that converts between the two. Enums must be a named int32 kind that
|
||||
// implements protoreflect.Enum, and messages must be pointer to a named
|
||||
// struct type that implements protoreflect.ProtoMessage.
|
||||
//
|
||||
// This matcher deliberately supports a wider range of Go types than what
|
||||
// protoc-gen-go historically generated to be able to automatically wrap some
|
||||
// v1 messages generated by other forks of protoc-gen-go.
|
||||
func NewConverter(t reflect.Type, k pref.Kind) Converter {
|
||||
return NewLegacyConverter(t, k, nil)
|
||||
}
|
||||
|
||||
// LegacyWrapper is a set of wrapper methods that wraps legacy v1 Go types
|
||||
// to implement the v2 reflection APIs.
|
||||
type (
|
||||
LegacyWrapper interface {
|
||||
EnumOf(interface{}) LegacyEnum
|
||||
EnumTypeOf(interface{}) pref.EnumType
|
||||
EnumDescriptorOf(interface{}) pref.EnumDescriptor
|
||||
|
||||
MessageOf(interface{}) LegacyMessage
|
||||
MessageTypeOf(interface{}) pref.MessageType
|
||||
MessageDescriptorOf(interface{}) pref.MessageDescriptor
|
||||
|
||||
// TODO: Remove these eventually.
|
||||
// See the TODOs in internal/impl/legacy_extension.go.
|
||||
ExtensionDescFromType(pref.ExtensionType) *piface.ExtensionDescV1
|
||||
ExtensionTypeFromDesc(*piface.ExtensionDescV1) pref.ExtensionType
|
||||
}
|
||||
|
||||
LegacyEnum = interface {
|
||||
pref.Enum
|
||||
ProtoUnwrap() interface{}
|
||||
}
|
||||
|
||||
LegacyMessage = interface {
|
||||
pref.Message
|
||||
ProtoUnwrap() interface{}
|
||||
}
|
||||
)
|
||||
|
||||
// NewLegacyConverter is identical to NewConverter,
|
||||
// but supports wrapping legacy v1 messages to implement the v2 message API
|
||||
// using the provided LegacyWrapper.
|
||||
func NewLegacyConverter(t reflect.Type, k pref.Kind, w LegacyWrapper) Converter {
|
||||
switch k {
|
||||
case pref.BoolKind:
|
||||
if t.Kind() == reflect.Bool {
|
||||
return makeScalarConverter(t, boolType)
|
||||
return newScalarConverter(t, boolType)
|
||||
}
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
if t.Kind() == reflect.Int32 {
|
||||
return makeScalarConverter(t, int32Type)
|
||||
return newScalarConverter(t, int32Type)
|
||||
}
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
if t.Kind() == reflect.Int64 {
|
||||
return makeScalarConverter(t, int64Type)
|
||||
return newScalarConverter(t, int64Type)
|
||||
}
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
if t.Kind() == reflect.Uint32 {
|
||||
return makeScalarConverter(t, uint32Type)
|
||||
return newScalarConverter(t, uint32Type)
|
||||
}
|
||||
case pref.Uint64Kind, pref.Fixed64Kind:
|
||||
if t.Kind() == reflect.Uint64 {
|
||||
return makeScalarConverter(t, uint64Type)
|
||||
return newScalarConverter(t, uint64Type)
|
||||
}
|
||||
case pref.FloatKind:
|
||||
if t.Kind() == reflect.Float32 {
|
||||
return makeScalarConverter(t, float32Type)
|
||||
return newScalarConverter(t, float32Type)
|
||||
}
|
||||
case pref.DoubleKind:
|
||||
if t.Kind() == reflect.Float64 {
|
||||
return makeScalarConverter(t, float64Type)
|
||||
return newScalarConverter(t, float64Type)
|
||||
}
|
||||
case pref.StringKind:
|
||||
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
|
||||
return makeScalarConverter(t, stringType)
|
||||
return newScalarConverter(t, stringType)
|
||||
}
|
||||
case pref.BytesKind:
|
||||
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
|
||||
return makeScalarConverter(t, bytesType)
|
||||
return newScalarConverter(t, bytesType)
|
||||
}
|
||||
case pref.EnumKind:
|
||||
// Handle enums, which must be a named int32 type.
|
||||
if t.PkgPath() != "" && t.Kind() == reflect.Int32 {
|
||||
var et pref.EnumType
|
||||
if t.Implements(enumIfaceV2) {
|
||||
et = &enumType{reflect.Zero(t).Interface().(pref.Enum).Descriptor(), t}
|
||||
} else {
|
||||
et = w.EnumTypeOf(reflect.Zero(t).Interface())
|
||||
}
|
||||
if t.Implements(enumIfaceV2) && t.Kind() == reflect.Int32 {
|
||||
return Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != t {
|
||||
@ -139,44 +95,38 @@ func NewLegacyConverter(t reflect.Type, k pref.Kind, w LegacyWrapper) Converter
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
return reflect.ValueOf(v.Enum()).Convert(t)
|
||||
},
|
||||
EnumType: et,
|
||||
IsLegacy: !t.Implements(enumIfaceV2),
|
||||
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
||||
return reflect.ValueOf(n).Convert(t).Interface().(pref.Enum)
|
||||
},
|
||||
}
|
||||
}
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
// Handle v2 messages, which must satisfy the proto.Message interface.
|
||||
if t.Kind() == reflect.Ptr && t.Implements(messageIfaceV2) {
|
||||
md := reflect.Zero(t).Interface().(pref.ProtoMessage).ProtoReflect().Descriptor()
|
||||
mt := &messageType{md, t}
|
||||
return NewMessageConverter(mt)
|
||||
}
|
||||
|
||||
// Handle v1 messages, which we need to wrap as a v2 message.
|
||||
if w != nil && t.Kind() == reflect.Ptr && t.Implements(messageIfaceV1) {
|
||||
mt := w.MessageTypeOf(reflect.Zero(t).Interface())
|
||||
if t.Implements(messageIfaceV2) && t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
|
||||
return Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
||||
}
|
||||
return pref.ValueOf(w.MessageOf(v.Interface()))
|
||||
return pref.ValueOf(v.Interface().(pref.ProtoMessage).ProtoReflect())
|
||||
},
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(v.Message().(Unwrapper).ProtoUnwrap())
|
||||
rv := reflect.ValueOf(v.Message().Interface())
|
||||
if rv.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), t))
|
||||
}
|
||||
return rv
|
||||
},
|
||||
MessageType: mt,
|
||||
IsLegacy: true,
|
||||
NewMessage: func() pref.Message {
|
||||
return reflect.New(t.Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("invalid Go type %v for protobuf kind %v", t, k))
|
||||
}
|
||||
|
||||
func makeScalarConverter(goType, pbType reflect.Type) Converter {
|
||||
func newScalarConverter(goType, pbType reflect.Type) Converter {
|
||||
return Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != goType {
|
||||
@ -200,83 +150,11 @@ func makeScalarConverter(goType, pbType reflect.Type) Converter {
|
||||
}
|
||||
}
|
||||
|
||||
// NewEnumConverter returns a converter for an EnumType, whose GoType must implement protoreflect.Enum.
|
||||
func NewEnumConverter(et pref.EnumType) Converter {
|
||||
t := et.GoType()
|
||||
if !t.Implements(enumIfaceV2) {
|
||||
panic(fmt.Sprintf("invalid type: %v does not implement %v", t, enumIfaceV2))
|
||||
}
|
||||
return Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
||||
}
|
||||
e := v.Interface().(pref.Enum)
|
||||
return pref.ValueOf(e.Number())
|
||||
},
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
return reflect.ValueOf(et.New(v.Enum()))
|
||||
},
|
||||
EnumType: et,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMessageConverter returns a converter for a MessageType, whose GoType must implement protoreflect.ProtoMessage.
|
||||
func NewMessageConverter(mt pref.MessageType) Converter {
|
||||
t := mt.GoType()
|
||||
if !t.Implements(messageIfaceV2) {
|
||||
panic(fmt.Sprintf("invalid type: %v does not implement %v", t, messageIfaceV2))
|
||||
}
|
||||
return Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), t))
|
||||
}
|
||||
return pref.ValueOf(v.Interface().(pref.ProtoMessage).ProtoReflect())
|
||||
},
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(v.Message().Interface())
|
||||
if rv.Type() != t {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), t))
|
||||
}
|
||||
return rv
|
||||
},
|
||||
MessageType: mt,
|
||||
}
|
||||
}
|
||||
|
||||
// Converter provides functions for converting to/from Go reflect.Value types
|
||||
// and protobuf protoreflect.Value types.
|
||||
type Converter struct {
|
||||
PBValueOf func(reflect.Value) pref.Value
|
||||
GoValueOf func(pref.Value) reflect.Value
|
||||
EnumType pref.EnumType
|
||||
MessageType pref.MessageType
|
||||
IsLegacy bool
|
||||
}
|
||||
|
||||
// TODO: This needs to be centralized in a package.
|
||||
type enumType struct {
|
||||
// TODO: Remove me as an embedded field.
|
||||
pref.EnumDescriptor
|
||||
typ reflect.Type // must implement protoreflect.Enum
|
||||
}
|
||||
|
||||
func (t *enumType) Descriptor() pref.EnumDescriptor { return t.EnumDescriptor }
|
||||
func (t *enumType) GoType() reflect.Type { return t.typ }
|
||||
func (t *enumType) New(n pref.EnumNumber) pref.Enum {
|
||||
return reflect.ValueOf(n).Convert(t.typ).Interface().(pref.Enum)
|
||||
}
|
||||
|
||||
// TODO: This needs to be centralized in a package.
|
||||
type messageType struct {
|
||||
// TODO: Remove me as an embedded field.
|
||||
pref.MessageDescriptor
|
||||
typ reflect.Type // must implement protoreflect.ProtoMessage
|
||||
}
|
||||
|
||||
func (t *messageType) Descriptor() pref.MessageDescriptor { return t.MessageDescriptor }
|
||||
func (t *messageType) GoType() reflect.Type { return t.typ }
|
||||
func (t *messageType) New() pref.Message {
|
||||
return reflect.New(t.typ.Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
|
||||
PBValueOf func(reflect.Value) pref.Value
|
||||
GoValueOf func(pref.Value) reflect.Value
|
||||
NewEnum func(pref.EnumNumber) pref.Enum
|
||||
NewMessage func() pref.Message
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ func (ls listReflect) Truncate(i int) {
|
||||
ls.v.Elem().Set(ls.v.Elem().Slice(0, i))
|
||||
}
|
||||
func (ls listReflect) NewMessage() pref.Message {
|
||||
return ls.conv.MessageType.New()
|
||||
return ls.conv.NewMessage()
|
||||
}
|
||||
func (ls listReflect) ProtoUnwrap() interface{} {
|
||||
return ls.v.Interface()
|
||||
|
@ -77,7 +77,7 @@ func (ms mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
|
||||
}
|
||||
}
|
||||
func (ms mapReflect) NewMessage() pref.Message {
|
||||
return ms.valConv.MessageType.New()
|
||||
return ms.valConv.NewMessage()
|
||||
}
|
||||
func (ms mapReflect) ProtoUnwrap() interface{} {
|
||||
return ms.v.Interface()
|
||||
|
358
reflect/prototype/type.go
Normal file
358
reflect/prototype/type.go
Normal file
@ -0,0 +1,358 @@
|
||||
// Copyright 2019 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 prototype provides constructors for protoreflect.EnumType,
|
||||
// protoreflect.MessageType, and protoreflect.ExtensionType.
|
||||
package prototype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/descfmt"
|
||||
"google.golang.org/protobuf/internal/value"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// Enum is a protoreflect.EnumType which combines a
|
||||
// protoreflect.EnumDescriptor with a constructor function.
|
||||
//
|
||||
// Both EnumDescriptor and NewEnum must be populated.
|
||||
// Once constructed, the exported fields must not be modified.
|
||||
type Enum struct {
|
||||
protoreflect.EnumDescriptor
|
||||
|
||||
// NewEnum constructs a new protoreflect.Enum representing the provided
|
||||
// enum number. The returned Go type must be identical for every call.
|
||||
NewEnum func(protoreflect.EnumNumber) protoreflect.Enum
|
||||
|
||||
once sync.Once
|
||||
goType reflect.Type
|
||||
}
|
||||
|
||||
func (t *Enum) New(n protoreflect.EnumNumber) protoreflect.Enum {
|
||||
e := t.NewEnum(n)
|
||||
t.once.Do(func() {
|
||||
t.goType = reflect.TypeOf(e)
|
||||
if e.Descriptor() != t.Descriptor() {
|
||||
panic(fmt.Sprintf("mismatching enum descriptor: got %v, want %v", e.Descriptor(), t.Descriptor()))
|
||||
}
|
||||
if e.Descriptor().IsPlaceholder() {
|
||||
panic("enum descriptor must not be a placeholder")
|
||||
}
|
||||
})
|
||||
if t.goType != reflect.TypeOf(e) {
|
||||
panic(fmt.Sprintf("mismatching types for enum: got %T, want %v", e, t.goType))
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (t *Enum) GoType() reflect.Type {
|
||||
t.New(0) // initialize t.typ
|
||||
return t.goType
|
||||
}
|
||||
|
||||
func (t *Enum) Descriptor() protoreflect.EnumDescriptor {
|
||||
return t.EnumDescriptor
|
||||
}
|
||||
|
||||
func (t *Enum) Format(s fmt.State, r rune) {
|
||||
descfmt.FormatDesc(s, r, t)
|
||||
}
|
||||
|
||||
// Message is a protoreflect.MessageType which combines a
|
||||
// protoreflect.MessageDescriptor with a constructor function.
|
||||
//
|
||||
// Both MessageDescriptor and NewMessage must be populated.
|
||||
// Once constructed, the exported fields must not be modified.
|
||||
type Message struct {
|
||||
protoreflect.MessageDescriptor
|
||||
|
||||
// NewMessage constructs an empty, newly allocated protoreflect.Message.
|
||||
// The returned Go type must be identical for every call.
|
||||
NewMessage func() protoreflect.Message
|
||||
|
||||
once sync.Once
|
||||
goType reflect.Type
|
||||
}
|
||||
|
||||
func (t *Message) New() protoreflect.Message {
|
||||
m := t.NewMessage()
|
||||
mi := m.Interface()
|
||||
t.once.Do(func() {
|
||||
t.goType = reflect.TypeOf(mi)
|
||||
if m.Descriptor() != t.Descriptor() {
|
||||
panic(fmt.Sprintf("mismatching message descriptor: got %v, want %v", m.Descriptor(), t.Descriptor()))
|
||||
}
|
||||
if m.Descriptor().IsPlaceholder() {
|
||||
panic("message descriptor must not be a placeholder")
|
||||
}
|
||||
})
|
||||
if t.goType != reflect.TypeOf(mi) {
|
||||
panic(fmt.Sprintf("mismatching types for message: got %T, want %v", mi, t.goType))
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func (t *Message) GoType() reflect.Type {
|
||||
t.New() // initialize t.goType
|
||||
return t.goType
|
||||
}
|
||||
|
||||
func (t *Message) Descriptor() protoreflect.MessageDescriptor {
|
||||
return t.MessageDescriptor
|
||||
}
|
||||
|
||||
func (t *Message) Format(s fmt.State, r rune) {
|
||||
descfmt.FormatDesc(s, r, t)
|
||||
}
|
||||
|
||||
// Extension is a protoreflect.ExtensionType which combines a
|
||||
// protoreflect.ExtensionDescriptor with a constructor function.
|
||||
//
|
||||
// ExtensionDescriptor must be populated, while NewEnum or NewMessage must
|
||||
// populated depending on the kind of the extension field.
|
||||
// Once constructed, the exported fields must not be modified.
|
||||
type Extension struct {
|
||||
protoreflect.ExtensionDescriptor
|
||||
|
||||
// NewEnum constructs a new enum (see Enum.NewEnum).
|
||||
// This must be populated if and only if ExtensionDescriptor.Kind
|
||||
// is a protoreflect.EnumKind.
|
||||
NewEnum func(protoreflect.EnumNumber) protoreflect.Enum
|
||||
|
||||
// NewMessage constructs a new message (see Enum.NewMessage).
|
||||
// This must be populated if and only if ExtensionDescriptor.Kind
|
||||
// is a protoreflect.MessageKind or protoreflect.GroupKind.
|
||||
NewMessage func() protoreflect.Message
|
||||
|
||||
// TODO: Allow users to manually set new, valueOf, and interfaceOf.
|
||||
// This allows users to implement custom composite types (e.g., List) or
|
||||
// custom Go types for primitives (e.g., int32).
|
||||
|
||||
once sync.Once
|
||||
goType reflect.Type
|
||||
new func() protoreflect.Value
|
||||
valueOf func(v interface{}) protoreflect.Value
|
||||
interfaceOf func(v protoreflect.Value) interface{}
|
||||
}
|
||||
|
||||
func (t *Extension) New() protoreflect.Value {
|
||||
t.lazyInit()
|
||||
pv := t.new()
|
||||
v := t.interfaceOf(pv)
|
||||
if reflect.TypeOf(v) != t.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.goType))
|
||||
}
|
||||
return pv
|
||||
}
|
||||
|
||||
func (t *Extension) ValueOf(v interface{}) protoreflect.Value {
|
||||
t.lazyInit()
|
||||
if reflect.TypeOf(v) != t.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, t.goType))
|
||||
}
|
||||
return t.valueOf(v)
|
||||
}
|
||||
|
||||
func (t *Extension) InterfaceOf(v protoreflect.Value) interface{} {
|
||||
t.lazyInit()
|
||||
vi := t.interfaceOf(v)
|
||||
if reflect.TypeOf(vi) != t.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", vi, t.goType))
|
||||
}
|
||||
return vi
|
||||
}
|
||||
|
||||
// GoType is the type of the extension field.
|
||||
// The type is T for scalars and *[]T for lists (maps are not allowed).
|
||||
// The type T is determined as follows:
|
||||
//
|
||||
// +------------+-------------------------------------+
|
||||
// | Go type | Protobuf kind |
|
||||
// +------------+-------------------------------------+
|
||||
// | bool | BoolKind |
|
||||
// | int32 | Int32Kind, Sint32Kind, Sfixed32Kind |
|
||||
// | int64 | Int64Kind, Sint64Kind, Sfixed64Kind |
|
||||
// | uint32 | Uint32Kind, Fixed32Kind |
|
||||
// | uint64 | Uint64Kind, Fixed64Kind |
|
||||
// | float32 | FloatKind |
|
||||
// | float64 | DoubleKind |
|
||||
// | string | StringKind |
|
||||
// | []byte | BytesKind |
|
||||
// | E | EnumKind |
|
||||
// | M | MessageKind, GroupKind |
|
||||
// +------------+-------------------------------------+
|
||||
//
|
||||
// The type E is the concrete enum type returned by NewEnum,
|
||||
// which is often, but not required to be, a named int32 type.
|
||||
// The type M is the concrete message type returned by NewMessage,
|
||||
// which is often, but not required to be, a pointer to a named struct type.
|
||||
func (t *Extension) GoType() reflect.Type {
|
||||
t.lazyInit()
|
||||
return t.goType
|
||||
}
|
||||
|
||||
func (t *Extension) Descriptor() protoreflect.ExtensionDescriptor {
|
||||
return t.ExtensionDescriptor
|
||||
}
|
||||
|
||||
func (t *Extension) Format(s fmt.State, r rune) {
|
||||
descfmt.FormatDesc(s, r, t)
|
||||
}
|
||||
|
||||
func (t *Extension) lazyInit() {
|
||||
t.once.Do(func() {
|
||||
switch t.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
if t.NewEnum == nil || t.NewMessage != nil {
|
||||
panic("NewEnum alone must be set")
|
||||
}
|
||||
e := t.NewEnum(0)
|
||||
if e.Descriptor() != t.Enum() {
|
||||
panic(fmt.Sprintf("mismatching enum descriptor: got %v, want %v", e.Descriptor(), t.Enum()))
|
||||
}
|
||||
t.goType = reflect.TypeOf(e)
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
if t.NewEnum != nil || t.NewMessage == nil {
|
||||
panic("NewMessage alone must be set")
|
||||
}
|
||||
m := t.NewMessage()
|
||||
if m.Descriptor() != t.Message() {
|
||||
panic(fmt.Sprintf("mismatching message descriptor: got %v, want %v", m.Descriptor(), t.Message()))
|
||||
}
|
||||
t.goType = reflect.TypeOf(m.Interface())
|
||||
default:
|
||||
if t.NewEnum != nil || t.NewMessage != nil {
|
||||
panic("neither NewEnum nor NewMessage may be set")
|
||||
}
|
||||
t.goType = goTypeForPBKind[t.Kind()]
|
||||
}
|
||||
|
||||
switch t.Cardinality() {
|
||||
case protoreflect.Optional:
|
||||
switch t.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
t.new = func() protoreflect.Value {
|
||||
return t.Default()
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
ev := v.(protoreflect.Enum)
|
||||
return protoreflect.ValueOf(ev.Number())
|
||||
}
|
||||
t.interfaceOf = func(v protoreflect.Value) interface{} {
|
||||
return t.NewEnum(v.Enum())
|
||||
}
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
t.new = func() protoreflect.Value {
|
||||
return protoreflect.ValueOf(t.NewMessage())
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
mv := v.(protoreflect.ProtoMessage).ProtoReflect()
|
||||
return protoreflect.ValueOf(mv)
|
||||
}
|
||||
t.interfaceOf = func(v protoreflect.Value) interface{} {
|
||||
return v.Message().Interface()
|
||||
}
|
||||
default:
|
||||
t.new = func() protoreflect.Value {
|
||||
v := t.Default()
|
||||
if t.Kind() == protoreflect.BytesKind {
|
||||
// Copy default bytes to avoid aliasing the original.
|
||||
v = protoreflect.ValueOf(append([]byte(nil), v.Bytes()...))
|
||||
}
|
||||
return v
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
return protoreflect.ValueOf(v)
|
||||
}
|
||||
t.interfaceOf = func(v protoreflect.Value) interface{} {
|
||||
return v.Interface()
|
||||
}
|
||||
}
|
||||
case protoreflect.Repeated:
|
||||
var conv value.Converter
|
||||
elemType := t.goType
|
||||
switch t.Kind() {
|
||||
case protoreflect.EnumKind:
|
||||
conv = value.Converter{
|
||||
PBValueOf: func(v reflect.Value) protoreflect.Value {
|
||||
if v.Type() != elemType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), elemType))
|
||||
}
|
||||
e := v.Interface().(protoreflect.Enum)
|
||||
return protoreflect.ValueOf(e.Number())
|
||||
},
|
||||
GoValueOf: func(v protoreflect.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(t.NewEnum(v.Enum()))
|
||||
if rv.Type() != elemType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), elemType))
|
||||
}
|
||||
return rv
|
||||
},
|
||||
NewEnum: t.NewEnum,
|
||||
}
|
||||
case protoreflect.MessageKind, protoreflect.GroupKind:
|
||||
conv = value.Converter{
|
||||
PBValueOf: func(v reflect.Value) protoreflect.Value {
|
||||
if v.Type() != elemType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), elemType))
|
||||
}
|
||||
m := v.Interface().(protoreflect.ProtoMessage).ProtoReflect()
|
||||
return protoreflect.ValueOf(m)
|
||||
},
|
||||
GoValueOf: func(v protoreflect.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(v.Message().Interface())
|
||||
if rv.Type() != elemType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), elemType))
|
||||
}
|
||||
return rv
|
||||
},
|
||||
NewMessage: t.NewMessage,
|
||||
}
|
||||
default:
|
||||
conv = value.NewConverter(elemType, t.Kind())
|
||||
}
|
||||
|
||||
t.goType = reflect.PtrTo(reflect.SliceOf(elemType))
|
||||
t.new = func() protoreflect.Value {
|
||||
v := reflect.New(t.goType.Elem()).Interface()
|
||||
return protoreflect.ValueOf(value.ListOf(v, conv))
|
||||
}
|
||||
t.valueOf = func(v interface{}) protoreflect.Value {
|
||||
return protoreflect.ValueOf(value.ListOf(v, conv))
|
||||
}
|
||||
t.interfaceOf = func(v protoreflect.Value) interface{} {
|
||||
return v.List().(value.Unwrapper).ProtoUnwrap()
|
||||
}
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid cardinality: %v", t.Cardinality()))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var goTypeForPBKind = map[protoreflect.Kind]reflect.Type{
|
||||
protoreflect.BoolKind: reflect.TypeOf(bool(false)),
|
||||
protoreflect.Int32Kind: reflect.TypeOf(int32(0)),
|
||||
protoreflect.Sint32Kind: reflect.TypeOf(int32(0)),
|
||||
protoreflect.Sfixed32Kind: reflect.TypeOf(int32(0)),
|
||||
protoreflect.Int64Kind: reflect.TypeOf(int64(0)),
|
||||
protoreflect.Sint64Kind: reflect.TypeOf(int64(0)),
|
||||
protoreflect.Sfixed64Kind: reflect.TypeOf(int64(0)),
|
||||
protoreflect.Uint32Kind: reflect.TypeOf(uint32(0)),
|
||||
protoreflect.Fixed32Kind: reflect.TypeOf(uint32(0)),
|
||||
protoreflect.Uint64Kind: reflect.TypeOf(uint64(0)),
|
||||
protoreflect.Fixed64Kind: reflect.TypeOf(uint64(0)),
|
||||
protoreflect.FloatKind: reflect.TypeOf(float32(0)),
|
||||
protoreflect.DoubleKind: reflect.TypeOf(float64(0)),
|
||||
protoreflect.StringKind: reflect.TypeOf(string("")),
|
||||
protoreflect.BytesKind: reflect.TypeOf([]byte(nil)),
|
||||
}
|
||||
|
||||
var (
|
||||
_ protoreflect.EnumType = (*Enum)(nil)
|
||||
_ protoreflect.MessageType = (*Message)(nil)
|
||||
_ protoreflect.ExtensionType = (*Extension)(nil)
|
||||
)
|
Loading…
Reference in New Issue
Block a user