mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-03-15 22:20:52 +00:00
all: refactor Converter
A Converter converts between reflect.Values and protoreflect.Values. The existing usage of Converter is somewhat confusing: The internal/value package creates Converters for scalar types only, the internal/impl package creates Converters for legacy messages and enums, and the reflect/prototype package creates Converters for repeated fields. Change the Converter type to an interface. The constructor for Converter takes a FieldDescriptor and reflect.Type, and directly handles conversions for all field types: Scalars, lists, maps, and legacy types. Move Converter into the internal/impl package, since that package contains the necessary support for dealing with legacy messages and enums. Drop the internal/value package. Replace two uses of prototype.Extension with more focused implementations, since the implementation is trivial with the refactored Converter. Drop prototype.Extension for the moment since it is now unused. Change-Id: If0c570fefac002cc5925b3d56281b6eb17e90d5f Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/187857 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
parent
f542220747
commit
954bd92c19
@ -7,8 +7,11 @@
|
||||
package filetype
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/descfmt"
|
||||
"google.golang.org/protobuf/internal/descopts"
|
||||
fdesc "google.golang.org/protobuf/internal/filedesc"
|
||||
pimpl "google.golang.org/protobuf/internal/impl"
|
||||
@ -223,24 +226,26 @@ func (tb TypeBuilder) Build() (out struct {
|
||||
var depIdx int32
|
||||
out.Extensions = make([]Extension, len(fbOut.Extensions))
|
||||
for i := range fbOut.Extensions {
|
||||
out.Extensions[i] = Extension{Extension: ptype.Extension{
|
||||
ExtensionDescriptor: &fbOut.Extensions[i],
|
||||
}}
|
||||
|
||||
// For enum and message kinds, determine the referent Go type so
|
||||
// that we can construct their constructors.
|
||||
const listExtDeps = 2
|
||||
var goType reflect.Type
|
||||
switch fbOut.Extensions[i].L1.Kind {
|
||||
case pref.EnumKind:
|
||||
j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
|
||||
goType := reflect.TypeOf(tb.GoTypes[j])
|
||||
out.Extensions[i].NewEnum = enumMaker(goType)
|
||||
goType = reflect.TypeOf(tb.GoTypes[j])
|
||||
depIdx++
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
|
||||
goType := reflect.TypeOf(tb.GoTypes[j])
|
||||
out.Extensions[i].NewMessage = messageMaker(goType)
|
||||
goType = reflect.TypeOf(tb.GoTypes[j])
|
||||
depIdx++
|
||||
default:
|
||||
goType = goTypeForPBKind[fbOut.Extensions[i].L1.Kind]
|
||||
}
|
||||
|
||||
out.Extensions[i] = Extension{
|
||||
ExtensionDescriptor: &fbOut.Extensions[i],
|
||||
goType: goType,
|
||||
}
|
||||
|
||||
// Keep v1 and v2 extensions in sync.
|
||||
@ -259,6 +264,24 @@ func (tb TypeBuilder) Build() (out struct {
|
||||
return out
|
||||
}
|
||||
|
||||
var goTypeForPBKind = map[pref.Kind]reflect.Type{
|
||||
pref.BoolKind: reflect.TypeOf(bool(false)),
|
||||
pref.Int32Kind: reflect.TypeOf(int32(0)),
|
||||
pref.Sint32Kind: reflect.TypeOf(int32(0)),
|
||||
pref.Sfixed32Kind: reflect.TypeOf(int32(0)),
|
||||
pref.Int64Kind: reflect.TypeOf(int64(0)),
|
||||
pref.Sint64Kind: reflect.TypeOf(int64(0)),
|
||||
pref.Sfixed64Kind: reflect.TypeOf(int64(0)),
|
||||
pref.Uint32Kind: reflect.TypeOf(uint32(0)),
|
||||
pref.Fixed32Kind: reflect.TypeOf(uint32(0)),
|
||||
pref.Uint64Kind: reflect.TypeOf(uint64(0)),
|
||||
pref.Fixed64Kind: reflect.TypeOf(uint64(0)),
|
||||
pref.FloatKind: reflect.TypeOf(float32(0)),
|
||||
pref.DoubleKind: reflect.TypeOf(float64(0)),
|
||||
pref.StringKind: reflect.TypeOf(string("")),
|
||||
pref.BytesKind: reflect.TypeOf([]byte(nil)),
|
||||
}
|
||||
|
||||
type depIdxs []int32
|
||||
|
||||
// Get retrieves the jth element of the ith sub-list.
|
||||
@ -310,14 +333,33 @@ func messageMaker(t reflect.Type) func() pref.Message {
|
||||
}
|
||||
|
||||
type (
|
||||
Enum = ptype.Enum
|
||||
Message = ptype.Message
|
||||
Extension struct {
|
||||
ptype.Extension
|
||||
legacyDesc *piface.ExtensionDescV1
|
||||
}
|
||||
Enum = ptype.Enum
|
||||
Message = ptype.Message
|
||||
)
|
||||
|
||||
type Extension struct {
|
||||
pref.ExtensionDescriptor
|
||||
legacyDesc *piface.ExtensionDescV1
|
||||
|
||||
once sync.Once
|
||||
goType reflect.Type
|
||||
conv pimpl.Converter
|
||||
}
|
||||
|
||||
func (t *Extension) New() pref.Value { return t.lazyInit().New() }
|
||||
func (t *Extension) ValueOf(v interface{}) pref.Value {
|
||||
return t.lazyInit().PBValueOf(reflect.ValueOf(v))
|
||||
}
|
||||
func (t *Extension) InterfaceOf(v pref.Value) interface{} {
|
||||
return t.lazyInit().GoValueOf(v).Interface()
|
||||
}
|
||||
func (t *Extension) GoType() reflect.Type {
|
||||
t.lazyInit()
|
||||
return t.goType
|
||||
}
|
||||
func (t *Extension) Descriptor() pref.ExtensionDescriptor { return t.ExtensionDescriptor }
|
||||
func (t *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, t) }
|
||||
|
||||
// ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
|
||||
// to be able to retrieve a v1 ExtensionDesc.
|
||||
//
|
||||
@ -326,3 +368,13 @@ type (
|
||||
func (x *Extension) ProtoLegacyExtensionDesc() *piface.ExtensionDescV1 {
|
||||
return x.legacyDesc
|
||||
}
|
||||
|
||||
func (t *Extension) lazyInit() pimpl.Converter {
|
||||
t.once.Do(func() {
|
||||
if t.ExtensionDescriptor.Cardinality() == pref.Repeated {
|
||||
t.goType = reflect.PtrTo(reflect.SliceOf(t.goType))
|
||||
}
|
||||
t.conv = pimpl.NewConverter(t.goType, t.ExtensionDescriptor)
|
||||
})
|
||||
return t.conv
|
||||
}
|
||||
|
197
internal/impl/convert.go
Normal file
197
internal/impl/convert.go
Normal file
@ -0,0 +1,197 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// Unwrapper unwraps the value to the underlying value.
|
||||
// This is implemented by List and Map.
|
||||
type Unwrapper interface {
|
||||
ProtoUnwrap() interface{}
|
||||
}
|
||||
|
||||
// A Converter coverts to/from Go reflect.Value types and protobuf protoreflect.Value types.
|
||||
type Converter interface {
|
||||
PBValueOf(reflect.Value) pref.Value
|
||||
GoValueOf(pref.Value) reflect.Value
|
||||
New() pref.Value
|
||||
}
|
||||
|
||||
// NewConverter matches a Go type with a protobuf field and returns a Converter
|
||||
// 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, fd pref.FieldDescriptor) Converter {
|
||||
switch {
|
||||
case fd.IsList():
|
||||
return newListConverter(t, fd)
|
||||
case fd.IsMap():
|
||||
return newMapConverter(t, fd)
|
||||
default:
|
||||
return newSingularConverter(t, fd)
|
||||
}
|
||||
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
|
||||
}
|
||||
|
||||
var (
|
||||
boolType = reflect.TypeOf(bool(false))
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
stringType = reflect.TypeOf(string(""))
|
||||
bytesType = reflect.TypeOf([]byte(nil))
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
)
|
||||
|
||||
type scalarConverter struct {
|
||||
goType, pbType reflect.Type
|
||||
def pref.Value
|
||||
}
|
||||
|
||||
func newSingularConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
|
||||
switch fd.Kind() {
|
||||
case pref.BoolKind:
|
||||
if t.Kind() == reflect.Bool {
|
||||
return &scalarConverter{t, boolType, fd.Default()}
|
||||
}
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
if t.Kind() == reflect.Int32 {
|
||||
return &scalarConverter{t, int32Type, fd.Default()}
|
||||
}
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
if t.Kind() == reflect.Int64 {
|
||||
return &scalarConverter{t, int64Type, fd.Default()}
|
||||
}
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
if t.Kind() == reflect.Uint32 {
|
||||
return &scalarConverter{t, uint32Type, fd.Default()}
|
||||
}
|
||||
case pref.Uint64Kind, pref.Fixed64Kind:
|
||||
if t.Kind() == reflect.Uint64 {
|
||||
return &scalarConverter{t, uint64Type, fd.Default()}
|
||||
}
|
||||
case pref.FloatKind:
|
||||
if t.Kind() == reflect.Float32 {
|
||||
return &scalarConverter{t, float32Type, fd.Default()}
|
||||
}
|
||||
case pref.DoubleKind:
|
||||
if t.Kind() == reflect.Float64 {
|
||||
return &scalarConverter{t, float64Type, fd.Default()}
|
||||
}
|
||||
case pref.StringKind:
|
||||
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
|
||||
return &scalarConverter{t, stringType, fd.Default()}
|
||||
}
|
||||
case pref.BytesKind:
|
||||
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
|
||||
return &scalarConverter{t, bytesType, fd.Default()}
|
||||
}
|
||||
case pref.EnumKind:
|
||||
// Handle enums, which must be a named int32 type.
|
||||
if t.Kind() == reflect.Int32 {
|
||||
return newEnumConverter(t, fd)
|
||||
}
|
||||
case pref.MessageKind, pref.GroupKind:
|
||||
return newMessageConverter(t)
|
||||
}
|
||||
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
|
||||
}
|
||||
|
||||
func (c *scalarConverter) PBValueOf(v reflect.Value) pref.Value {
|
||||
if v.Type() != c.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
|
||||
}
|
||||
if c.goType.Kind() == reflect.String && c.pbType.Kind() == reflect.Slice && v.Len() == 0 {
|
||||
return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
|
||||
}
|
||||
return pref.ValueOf(v.Convert(c.pbType).Interface())
|
||||
}
|
||||
|
||||
func (c *scalarConverter) GoValueOf(v pref.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(v.Interface())
|
||||
if rv.Type() != c.pbType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.pbType))
|
||||
}
|
||||
if c.pbType.Kind() == reflect.String && c.goType.Kind() == reflect.Slice && rv.Len() == 0 {
|
||||
return reflect.Zero(c.goType) // ensure empty string is []byte(nil)
|
||||
}
|
||||
return rv.Convert(c.goType)
|
||||
}
|
||||
|
||||
func (c *scalarConverter) New() pref.Value {
|
||||
return c.def
|
||||
}
|
||||
|
||||
type enumConverter struct {
|
||||
goType reflect.Type
|
||||
def pref.Value
|
||||
}
|
||||
|
||||
func newEnumConverter(goType reflect.Type, fd pref.FieldDescriptor) Converter {
|
||||
return &enumConverter{goType, fd.Default()}
|
||||
}
|
||||
|
||||
func (c *enumConverter) PBValueOf(v reflect.Value) pref.Value {
|
||||
if v.Type() != c.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
|
||||
}
|
||||
return pref.ValueOf(pref.EnumNumber(v.Int()))
|
||||
}
|
||||
|
||||
func (c *enumConverter) GoValueOf(v pref.Value) reflect.Value {
|
||||
return reflect.ValueOf(v.Enum()).Convert(c.goType)
|
||||
}
|
||||
|
||||
func (c *enumConverter) New() pref.Value {
|
||||
return c.def
|
||||
}
|
||||
|
||||
type messageConverter struct {
|
||||
goType reflect.Type
|
||||
}
|
||||
|
||||
func newMessageConverter(goType reflect.Type) Converter {
|
||||
return &messageConverter{goType}
|
||||
}
|
||||
|
||||
func (c *messageConverter) PBValueOf(v reflect.Value) pref.Value {
|
||||
if v.Type() != c.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
|
||||
}
|
||||
if m, ok := v.Interface().(pref.ProtoMessage); ok {
|
||||
return pref.ValueOf(m.ProtoReflect())
|
||||
}
|
||||
return pref.ValueOf(legacyWrapMessage(v).ProtoReflect())
|
||||
}
|
||||
|
||||
func (c *messageConverter) GoValueOf(v pref.Value) reflect.Value {
|
||||
m := v.Message()
|
||||
var rv reflect.Value
|
||||
if u, ok := m.(Unwrapper); ok {
|
||||
rv = reflect.ValueOf(u.ProtoUnwrap())
|
||||
} else {
|
||||
rv = reflect.ValueOf(m.Interface())
|
||||
}
|
||||
if rv.Type() != c.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), c.goType))
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (c *messageConverter) New() pref.Value {
|
||||
return c.PBValueOf(reflect.New(c.goType.Elem()))
|
||||
}
|
@ -2,23 +2,40 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package value
|
||||
package impl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// ListOf returns a protoreflect.List view of p, which must be a *[]T.
|
||||
// If p is nil, this returns an empty, read-only list.
|
||||
func ListOf(p interface{}, c Converter) interface {
|
||||
pref.List
|
||||
Unwrapper
|
||||
} {
|
||||
// TODO: Validate that p is a *[]T?
|
||||
rv := reflect.ValueOf(p)
|
||||
return &listReflect{rv, c}
|
||||
type listConverter struct {
|
||||
goType reflect.Type
|
||||
c Converter
|
||||
}
|
||||
|
||||
func newListConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
|
||||
if t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Slice {
|
||||
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
|
||||
}
|
||||
return &listConverter{t, newSingularConverter(t.Elem().Elem(), fd)}
|
||||
}
|
||||
|
||||
func (c *listConverter) PBValueOf(v reflect.Value) pref.Value {
|
||||
if v.Type() != c.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
|
||||
}
|
||||
return pref.ValueOf(&listReflect{v, c.c})
|
||||
}
|
||||
|
||||
func (c *listConverter) GoValueOf(v pref.Value) reflect.Value {
|
||||
return v.List().(*listReflect).v
|
||||
}
|
||||
|
||||
func (c *listConverter) New() pref.Value {
|
||||
return c.PBValueOf(reflect.New(c.goType.Elem()))
|
||||
}
|
||||
|
||||
type listReflect struct {
|
||||
@ -45,7 +62,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.NewMessage()
|
||||
return ls.conv.New().Message()
|
||||
}
|
||||
func (ls *listReflect) ProtoUnwrap() interface{} {
|
||||
return ls.v.Interface()
|
@ -2,74 +2,80 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package value
|
||||
package impl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// MapOf returns a protoreflect.Map view of p, which must a *map[K]V.
|
||||
// If p is nil, this returns an empty, read-only map.
|
||||
func MapOf(p interface{}, kc, kv Converter) interface {
|
||||
pref.Map
|
||||
Unwrapper
|
||||
} {
|
||||
// TODO: Validate that p is a *map[K]V?
|
||||
rv := reflect.ValueOf(p)
|
||||
return &mapReflect{rv, kc, kv}
|
||||
type mapConverter struct {
|
||||
goType reflect.Type
|
||||
keyConv, valConv Converter
|
||||
}
|
||||
|
||||
func newMapConverter(t reflect.Type, fd pref.FieldDescriptor) Converter {
|
||||
if t.Kind() != reflect.Map {
|
||||
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
|
||||
}
|
||||
return &mapConverter{
|
||||
goType: t,
|
||||
keyConv: newSingularConverter(t.Key(), fd.MapKey()),
|
||||
valConv: newSingularConverter(t.Elem(), fd.MapValue()),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *mapConverter) PBValueOf(v reflect.Value) pref.Value {
|
||||
if v.Type() != c.goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), c.goType))
|
||||
}
|
||||
return pref.ValueOf(&mapReflect{v, c.keyConv, c.valConv})
|
||||
}
|
||||
|
||||
func (c *mapConverter) GoValueOf(v pref.Value) reflect.Value {
|
||||
return v.Map().(*mapReflect).v
|
||||
}
|
||||
|
||||
func (c *mapConverter) New() pref.Value {
|
||||
return c.PBValueOf(reflect.MakeMap(c.goType))
|
||||
}
|
||||
|
||||
type mapReflect struct {
|
||||
v reflect.Value // *map[K]V
|
||||
v reflect.Value // map[K]V
|
||||
keyConv Converter
|
||||
valConv Converter
|
||||
}
|
||||
|
||||
func (ms *mapReflect) Len() int {
|
||||
if ms.v.IsNil() {
|
||||
return 0
|
||||
}
|
||||
return ms.v.Elem().Len()
|
||||
return ms.v.Len()
|
||||
}
|
||||
func (ms *mapReflect) Has(k pref.MapKey) bool {
|
||||
if ms.v.IsNil() {
|
||||
return false
|
||||
}
|
||||
rk := ms.keyConv.GoValueOf(k.Value())
|
||||
rv := ms.v.Elem().MapIndex(rk)
|
||||
rv := ms.v.MapIndex(rk)
|
||||
return rv.IsValid()
|
||||
}
|
||||
func (ms *mapReflect) Get(k pref.MapKey) pref.Value {
|
||||
if ms.v.IsNil() {
|
||||
return pref.Value{}
|
||||
}
|
||||
rk := ms.keyConv.GoValueOf(k.Value())
|
||||
rv := ms.v.Elem().MapIndex(rk)
|
||||
rv := ms.v.MapIndex(rk)
|
||||
if !rv.IsValid() {
|
||||
return pref.Value{}
|
||||
}
|
||||
return ms.valConv.PBValueOf(rv)
|
||||
}
|
||||
func (ms *mapReflect) Set(k pref.MapKey, v pref.Value) {
|
||||
if ms.v.Elem().IsNil() {
|
||||
ms.v.Elem().Set(reflect.MakeMap(ms.v.Elem().Type()))
|
||||
}
|
||||
rk := ms.keyConv.GoValueOf(k.Value())
|
||||
rv := ms.valConv.GoValueOf(v)
|
||||
ms.v.Elem().SetMapIndex(rk, rv)
|
||||
ms.v.SetMapIndex(rk, rv)
|
||||
}
|
||||
func (ms *mapReflect) Clear(k pref.MapKey) {
|
||||
rk := ms.keyConv.GoValueOf(k.Value())
|
||||
ms.v.Elem().SetMapIndex(rk, reflect.Value{})
|
||||
ms.v.SetMapIndex(rk, reflect.Value{})
|
||||
}
|
||||
func (ms *mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
|
||||
if ms.v.IsNil() {
|
||||
return
|
||||
}
|
||||
for _, k := range ms.v.Elem().MapKeys() {
|
||||
if v := ms.v.Elem().MapIndex(k); v.IsValid() {
|
||||
for _, k := range ms.v.MapKeys() {
|
||||
if v := ms.v.MapIndex(k); v.IsValid() {
|
||||
pk := ms.keyConv.PBValueOf(k).MapKey()
|
||||
pv := ms.valConv.PBValueOf(v)
|
||||
if !f(pk, pv) {
|
||||
@ -79,7 +85,7 @@ func (ms *mapReflect) Range(f func(pref.MapKey, pref.Value) bool) {
|
||||
}
|
||||
}
|
||||
func (ms *mapReflect) NewMessage() pref.Message {
|
||||
return ms.valConv.NewMessage()
|
||||
return ms.valConv.New().Message()
|
||||
}
|
||||
func (ms *mapReflect) ProtoUnwrap() interface{} {
|
||||
return ms.v.Interface()
|
@ -11,7 +11,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/filedesc"
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/prototype"
|
||||
@ -80,8 +79,8 @@ func (e *legacyEnumWrapper) ProtoUnwrap() interface{} {
|
||||
}
|
||||
|
||||
var (
|
||||
_ pref.Enum = (*legacyEnumWrapper)(nil)
|
||||
_ pvalue.Unwrapper = (*legacyEnumWrapper)(nil)
|
||||
_ pref.Enum = (*legacyEnumWrapper)(nil)
|
||||
_ Unwrapper = (*legacyEnumWrapper)(nil)
|
||||
)
|
||||
|
||||
var legacyEnumDescCache sync.Map // map[reflect.Type]protoreflect.EnumDescriptor
|
||||
|
@ -12,10 +12,8 @@ import (
|
||||
"google.golang.org/protobuf/internal/descfmt"
|
||||
ptag "google.golang.org/protobuf/internal/encoding/tag"
|
||||
"google.golang.org/protobuf/internal/filedesc"
|
||||
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"
|
||||
)
|
||||
|
||||
@ -70,7 +68,7 @@ func legacyExtensionDescFromType(xt pref.ExtensionType) *piface.ExtensionDescV1
|
||||
// Create a new parent message and unwrap it if possible.
|
||||
mv := mt.New().Interface()
|
||||
t := reflect.TypeOf(mv)
|
||||
if mv, ok := mv.(pvalue.Unwrapper); ok {
|
||||
if mv, ok := mv.(Unwrapper); ok {
|
||||
t = reflect.TypeOf(mv.ProtoUnwrap())
|
||||
}
|
||||
|
||||
@ -198,7 +196,13 @@ func legacyExtensionTypeFromDesc(d *piface.ExtensionDescV1) pref.ExtensionType {
|
||||
xd.L1.Extendee = Export{}.MessageDescriptorOf(d.ExtendedType)
|
||||
xd.L2.Enum = ed
|
||||
xd.L2.Message = md
|
||||
xt := LegacyExtensionTypeOf(xd, t)
|
||||
tt := reflect.TypeOf(d.ExtensionType)
|
||||
if isOptional {
|
||||
tt = tt.Elem()
|
||||
} else if isRepeated {
|
||||
tt = reflect.PtrTo(tt)
|
||||
}
|
||||
xt := LegacyExtensionTypeOf(xd, tt)
|
||||
|
||||
// Cache the conversion for both directions.
|
||||
legacyExtensionDescCache.LoadOrStore(xt, d)
|
||||
@ -209,82 +213,30 @@ func legacyExtensionTypeFromDesc(d *piface.ExtensionDescV1) pref.ExtensionType {
|
||||
}
|
||||
|
||||
// LegacyExtensionTypeOf returns a protoreflect.ExtensionType where the
|
||||
// element type of the field is t. The type t must be provided if the field
|
||||
// is an enum or message.
|
||||
// element type of the field is t.
|
||||
//
|
||||
// This is exported for testing purposes.
|
||||
func LegacyExtensionTypeOf(xd pref.ExtensionDescriptor, t reflect.Type) pref.ExtensionType {
|
||||
var conv pvalue.Converter
|
||||
var isLegacy bool
|
||||
xt := &prototype.Extension{ExtensionDescriptor: xd}
|
||||
switch xd.Kind() {
|
||||
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:
|
||||
// Extension types for non-enums and non-messages are simple.
|
||||
return &prototype.Extension{ExtensionDescriptor: xd}
|
||||
return &legacyExtensionType{
|
||||
ExtensionDescriptor: xd,
|
||||
typ: t,
|
||||
conv: NewConverter(t, xd),
|
||||
}
|
||||
if !isLegacy {
|
||||
return xt
|
||||
}
|
||||
|
||||
// Wrap ExtensionType such that GoType presents the legacy Go type.
|
||||
xt2 := &legacyExtensionType{ExtensionType: xt}
|
||||
if xd.Cardinality() != pref.Repeated {
|
||||
xt2.typ = t
|
||||
xt2.new = func() pref.Value {
|
||||
return xt.New()
|
||||
}
|
||||
xt2.valueOf = func(v interface{}) pref.Value {
|
||||
if reflect.TypeOf(v) != xt2.typ {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, xt2.typ))
|
||||
}
|
||||
if xd.Kind() == pref.EnumKind {
|
||||
return xt.ValueOf(Export{}.EnumOf(v))
|
||||
} else {
|
||||
return xt.ValueOf(Export{}.MessageOf(v).Interface())
|
||||
}
|
||||
}
|
||||
xt2.interfaceOf = func(v pref.Value) interface{} {
|
||||
return xt.InterfaceOf(v).(pvalue.Unwrapper).ProtoUnwrap()
|
||||
}
|
||||
} else {
|
||||
xt2.typ = reflect.PtrTo(reflect.SliceOf(t))
|
||||
xt2.new = func() pref.Value {
|
||||
v := reflect.New(xt2.typ.Elem()).Interface()
|
||||
return pref.ValueOf(pvalue.ListOf(v, conv))
|
||||
}
|
||||
xt2.valueOf = func(v interface{}) pref.Value {
|
||||
if reflect.TypeOf(v) != xt2.typ {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, xt2.typ))
|
||||
}
|
||||
return pref.ValueOf(pvalue.ListOf(v, conv))
|
||||
}
|
||||
xt2.interfaceOf = func(pv pref.Value) interface{} {
|
||||
v := pv.List().(pvalue.Unwrapper).ProtoUnwrap()
|
||||
if reflect.TypeOf(v) != xt2.typ {
|
||||
panic(fmt.Sprintf("invalid type: got %T, want %v", v, xt2.typ))
|
||||
}
|
||||
return v
|
||||
}
|
||||
}
|
||||
return xt2
|
||||
}
|
||||
|
||||
type legacyExtensionType struct {
|
||||
pref.ExtensionType
|
||||
typ reflect.Type
|
||||
new func() pref.Value
|
||||
valueOf func(interface{}) pref.Value
|
||||
interfaceOf func(pref.Value) interface{}
|
||||
pref.ExtensionDescriptor
|
||||
typ reflect.Type
|
||||
conv Converter
|
||||
}
|
||||
|
||||
func (x *legacyExtensionType) GoType() reflect.Type { return x.typ }
|
||||
func (x *legacyExtensionType) New() pref.Value { return x.new() }
|
||||
func (x *legacyExtensionType) ValueOf(v interface{}) pref.Value { return x.valueOf(v) }
|
||||
func (x *legacyExtensionType) InterfaceOf(v pref.Value) interface{} { return x.interfaceOf(v) }
|
||||
func (x *legacyExtensionType) GoType() reflect.Type { return x.typ }
|
||||
func (x *legacyExtensionType) New() pref.Value { return x.conv.New() }
|
||||
func (x *legacyExtensionType) ValueOf(v interface{}) pref.Value {
|
||||
return x.conv.PBValueOf(reflect.ValueOf(v))
|
||||
}
|
||||
func (x *legacyExtensionType) InterfaceOf(v pref.Value) interface{} {
|
||||
return x.conv.GoValueOf(v).Interface()
|
||||
}
|
||||
func (x *legacyExtensionType) Descriptor() pref.ExtensionDescriptor { return x.ExtensionDescriptor }
|
||||
func (x *legacyExtensionType) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, x) }
|
||||
|
@ -56,10 +56,10 @@ func init() {
|
||||
preg.GlobalTypes.Register(mt)
|
||||
}
|
||||
|
||||
func mustMakeExtensionType(fileDesc, extDesc string, t interface{}, r pdesc.Resolver) pref.ExtensionType {
|
||||
func mustMakeExtensionType(fileDesc, extDesc string, t reflect.Type, r pdesc.Resolver) pref.ExtensionType {
|
||||
s := fmt.Sprintf(`name:"test.proto" syntax:"proto2" %s extension:[{%s}]`, fileDesc, extDesc)
|
||||
xd := mustMakeFileDesc(s, r).Extensions().Get(0)
|
||||
return pimpl.LegacyExtensionTypeOf(xd, reflect.TypeOf(t))
|
||||
return pimpl.LegacyExtensionTypeOf(xd, t)
|
||||
}
|
||||
|
||||
func mustMakeFileDesc(s string, r pdesc.Resolver) pref.FileDescriptor {
|
||||
@ -92,102 +92,102 @@ var (
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"optional_bool" number:10000 label:LABEL_OPTIONAL type:TYPE_BOOL default_value:"true" extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf(false), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"optional_int32" number:10001 label:LABEL_OPTIONAL type:TYPE_INT32 default_value:"-12345" extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf(int32(0)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"optional_uint32" number:10002 label:LABEL_OPTIONAL type:TYPE_UINT32 default_value:"3200" extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf(uint32(0)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"optional_float" number:10003 label:LABEL_OPTIONAL type:TYPE_FLOAT default_value:"3.14159" extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf(float32(0)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"optional_string" number:10004 label:LABEL_OPTIONAL type:TYPE_STRING default_value:"hello, \"world!\"\n" extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf(""), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"optional_bytes" number:10005 label:LABEL_OPTIONAL type:TYPE_BYTES default_value:"dead\\336\\255\\276\\357beef" extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf(([]byte)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
|
||||
`name:"optional_enum_v1" number:10006 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".google.golang.org.proto2_20180125.Message.ChildEnum" default_value:"ALPHA" extendee:".LegacyTestMessage"`,
|
||||
proto2_20180125.Message_ChildEnum(0), depReg,
|
||||
reflect.TypeOf(proto2_20180125.Message_ChildEnum(0)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
|
||||
`name:"optional_message_v1" number:10007 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message.ChildMessage" extendee:".LegacyTestMessage"`,
|
||||
(*proto2_20180125.Message_ChildMessage)(nil), depReg,
|
||||
reflect.TypeOf((*proto2_20180125.Message_ChildMessage)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "enum2.proto"]`,
|
||||
`name:"optional_enum_v2" number:10008 label:LABEL_OPTIONAL type:TYPE_ENUM type_name:".EnumProto2" default_value:"DEAD" extendee:".LegacyTestMessage"`,
|
||||
EnumProto2(0), depReg,
|
||||
reflect.TypeOf(EnumProto2(0)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "enum-messages.proto"]`,
|
||||
`name:"optional_message_v2" number:10009 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".EnumMessages" extendee:".LegacyTestMessage"`,
|
||||
(*EnumMessages)(nil), depReg,
|
||||
reflect.TypeOf((*EnumMessages)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"repeated_bool" number:10010 label:LABEL_REPEATED type:TYPE_BOOL extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf((*[]bool)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"repeated_int32" number:10011 label:LABEL_REPEATED type:TYPE_INT32 extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf((*[]int32)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"repeated_uint32" number:10012 label:LABEL_REPEATED type:TYPE_UINT32 extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf((*[]uint32)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"repeated_float" number:10013 label:LABEL_REPEATED type:TYPE_FLOAT extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf((*[]float32)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"repeated_string" number:10014 label:LABEL_REPEATED type:TYPE_STRING extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf((*[]string)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:"legacy.proto"`,
|
||||
`name:"repeated_bytes" number:10015 label:LABEL_REPEATED type:TYPE_BYTES extendee:".LegacyTestMessage"`,
|
||||
nil, depReg,
|
||||
reflect.TypeOf((*[][]byte)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
|
||||
`name:"repeated_enum_v1" number:10016 label:LABEL_REPEATED type:TYPE_ENUM type_name:".google.golang.org.proto2_20180125.Message.ChildEnum" extendee:".LegacyTestMessage"`,
|
||||
proto2_20180125.Message_ChildEnum(0), depReg,
|
||||
reflect.TypeOf((*[]proto2_20180125.Message_ChildEnum)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "proto2.v1.0.0-20180125-92554152/test.proto"]`,
|
||||
`name:"repeated_message_v1" number:10017 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".google.golang.org.proto2_20180125.Message.ChildMessage" extendee:".LegacyTestMessage"`,
|
||||
(*proto2_20180125.Message_ChildMessage)(nil), depReg,
|
||||
reflect.TypeOf((*[]*proto2_20180125.Message_ChildMessage)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "enum2.proto"]`,
|
||||
`name:"repeated_enum_v2" number:10018 label:LABEL_REPEATED type:TYPE_ENUM type_name:".EnumProto2" extendee:".LegacyTestMessage"`,
|
||||
EnumProto2(0), depReg,
|
||||
reflect.TypeOf((*[]EnumProto2)(nil)), depReg,
|
||||
),
|
||||
mustMakeExtensionType(
|
||||
`package:"fizz.buzz" dependency:["legacy.proto", "enum-messages.proto"]`,
|
||||
`name:"repeated_message_v2" number:10019 label:LABEL_REPEATED type:TYPE_MESSAGE type_name:".EnumMessages" extendee:".LegacyTestMessage"`,
|
||||
(*EnumMessages)(nil), depReg,
|
||||
reflect.TypeOf((*[](*EnumMessages))(nil)), depReg,
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
preg "google.golang.org/protobuf/reflect/protoregistry"
|
||||
piface "google.golang.org/protobuf/runtime/protoiface"
|
||||
@ -40,10 +39,11 @@ func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x export
|
||||
if !reflect.PtrTo(ot).Implements(ft) {
|
||||
panic(fmt.Sprintf("invalid type: %v does not implement %v", ot, ft))
|
||||
}
|
||||
conv, _ := newConverter(ot.Field(0).Type, fd.Kind())
|
||||
conv := NewConverter(ot.Field(0).Type, fd)
|
||||
isMessage := fd.Message() != nil
|
||||
var frozenEmpty pref.Value
|
||||
if conv.NewMessage != nil {
|
||||
frozenEmpty = pref.ValueOf(frozenMessage{conv.NewMessage()})
|
||||
if isMessage {
|
||||
frozenEmpty = pref.ValueOf(frozenMessage{conv.New().Message()})
|
||||
}
|
||||
|
||||
// TODO: Implement unsafe fast path?
|
||||
@ -97,7 +97,7 @@ func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x export
|
||||
rv.Set(conv.GoValueOf(v))
|
||||
},
|
||||
mutable: func(p pointer) pref.Value {
|
||||
if conv.NewMessage == nil {
|
||||
if !isMessage {
|
||||
panic("invalid Mutable on field with non-composite type")
|
||||
}
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
@ -106,11 +106,13 @@ func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x export
|
||||
}
|
||||
rv = rv.Elem().Elem().Field(0)
|
||||
if rv.IsNil() {
|
||||
rv.Set(conv.GoValueOf(pref.ValueOf(conv.NewMessage())))
|
||||
rv.Set(conv.GoValueOf(pref.ValueOf(conv.New().Message())))
|
||||
}
|
||||
return conv.PBValueOf(rv)
|
||||
},
|
||||
newMessage: conv.NewMessage,
|
||||
newMessage: func() pref.Message {
|
||||
return conv.New().Message()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,57 +121,8 @@ func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField, x exporter
|
||||
if ft.Kind() != reflect.Map {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want map kind", ft))
|
||||
}
|
||||
keyConv, _ := newConverter(ft.Key(), fd.MapKey().Kind())
|
||||
valConv, _ := newConverter(ft.Elem(), fd.MapValue().Kind())
|
||||
frozenEmpty := pref.ValueOf(frozenMap{
|
||||
pvalue.MapOf(reflect.Zero(reflect.PtrTo(fs.Type)).Interface(), keyConv, valConv),
|
||||
})
|
||||
|
||||
// TODO: Implement unsafe fast path?
|
||||
fieldOffset := offsetOf(fs, x)
|
||||
return fieldInfo{
|
||||
fieldDesc: fd,
|
||||
has: func(p pointer) bool {
|
||||
if p.IsNil() {
|
||||
return false
|
||||
}
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
return rv.Len() > 0
|
||||
},
|
||||
clear: func(p pointer) {
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
rv.Set(reflect.Zero(rv.Type()))
|
||||
},
|
||||
get: func(p pointer) pref.Value {
|
||||
if p.IsNil() {
|
||||
return frozenEmpty
|
||||
}
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
if rv.IsNil() {
|
||||
return frozenEmpty
|
||||
}
|
||||
return pref.ValueOf(pvalue.MapOf(rv.Addr().Interface(), keyConv, valConv))
|
||||
},
|
||||
set: func(p pointer, v pref.Value) {
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
rv.Set(reflect.ValueOf(v.Map().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
|
||||
},
|
||||
mutable: func(p pointer) pref.Value {
|
||||
v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
|
||||
return pref.ValueOf(pvalue.MapOf(v, keyConv, valConv))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
||||
ft := fs.Type
|
||||
if ft.Kind() != reflect.Slice {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
|
||||
}
|
||||
conv, _ := newConverter(ft.Elem(), fd.Kind())
|
||||
frozenEmpty := pref.ValueOf(frozenList{
|
||||
pvalue.ListOf(reflect.Zero(reflect.PtrTo(fs.Type)).Interface(), conv),
|
||||
})
|
||||
conv := NewConverter(ft, fd)
|
||||
frozenEmpty := pref.ValueOf(frozenMap{conv.New().Map()})
|
||||
|
||||
// TODO: Implement unsafe fast path?
|
||||
fieldOffset := offsetOf(fs, x)
|
||||
@ -194,15 +147,62 @@ func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField, x exporte
|
||||
if rv.Len() == 0 {
|
||||
return frozenEmpty
|
||||
}
|
||||
return pref.ValueOf(pvalue.ListOf(rv.Addr().Interface(), conv))
|
||||
return conv.PBValueOf(rv)
|
||||
},
|
||||
set: func(p pointer, v pref.Value) {
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
rv.Set(reflect.ValueOf(v.List().(pvalue.Unwrapper).ProtoUnwrap()).Elem())
|
||||
rv.Set(conv.GoValueOf(v))
|
||||
},
|
||||
mutable: func(p pointer) pref.Value {
|
||||
v := p.Apply(fieldOffset).AsIfaceOf(fs.Type)
|
||||
return pref.ValueOf(pvalue.ListOf(v, conv))
|
||||
v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
if v.IsNil() {
|
||||
v.Set(reflect.MakeMap(fs.Type))
|
||||
}
|
||||
return conv.PBValueOf(v)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
||||
ft := fs.Type
|
||||
if ft.Kind() != reflect.Slice {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
|
||||
}
|
||||
conv := NewConverter(reflect.PtrTo(ft), fd)
|
||||
frozenEmpty := pref.ValueOf(frozenList{conv.New().List()})
|
||||
|
||||
// TODO: Implement unsafe fast path?
|
||||
fieldOffset := offsetOf(fs, x)
|
||||
return fieldInfo{
|
||||
fieldDesc: fd,
|
||||
has: func(p pointer) bool {
|
||||
if p.IsNil() {
|
||||
return false
|
||||
}
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
return rv.Len() > 0
|
||||
},
|
||||
clear: func(p pointer) {
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
rv.Set(reflect.Zero(rv.Type()))
|
||||
},
|
||||
get: func(p pointer) pref.Value {
|
||||
if p.IsNil() {
|
||||
return frozenEmpty
|
||||
}
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
|
||||
if rv.Elem().Len() == 0 {
|
||||
return frozenEmpty
|
||||
}
|
||||
return conv.PBValueOf(rv)
|
||||
},
|
||||
set: func(p pointer, v pref.Value) {
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
rv.Set(reflect.ValueOf(v.List().(Unwrapper).ProtoUnwrap()).Elem())
|
||||
},
|
||||
mutable: func(p pointer) pref.Value {
|
||||
v := p.Apply(fieldOffset).AsValueOf(fs.Type)
|
||||
return conv.PBValueOf(v)
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -224,7 +224,7 @@ func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x expor
|
||||
ft = ft.Elem()
|
||||
}
|
||||
}
|
||||
conv, _ := newConverter(ft, fd.Kind())
|
||||
conv := NewConverter(ft, fd)
|
||||
|
||||
// TODO: Implement unsafe fast path?
|
||||
fieldOffset := offsetOf(fs, x)
|
||||
@ -372,8 +372,8 @@ func fieldInfoForWeakMessage(fd pref.FieldDescriptor, weakOffset offset) fieldIn
|
||||
|
||||
func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
||||
ft := fs.Type
|
||||
conv, _ := newConverter(ft, fd.Kind())
|
||||
frozenEmpty := pref.ValueOf(frozenMessage{conv.NewMessage()})
|
||||
conv := NewConverter(ft, fd)
|
||||
frozenEmpty := pref.ValueOf(frozenMessage{conv.New().Message()})
|
||||
|
||||
// TODO: Implement unsafe fast path?
|
||||
fieldOffset := offsetOf(fs, x)
|
||||
@ -410,11 +410,13 @@ func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x expo
|
||||
mutable: func(p pointer) pref.Value {
|
||||
rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
|
||||
if rv.IsNil() {
|
||||
rv.Set(conv.GoValueOf(pref.ValueOf(conv.NewMessage())))
|
||||
rv.Set(conv.GoValueOf(conv.New()))
|
||||
}
|
||||
return conv.PBValueOf(rv)
|
||||
},
|
||||
newMessage: conv.NewMessage,
|
||||
newMessage: func() pref.Message {
|
||||
return conv.New().Message()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,50 +448,6 @@ var (
|
||||
messageIfaceV2 = reflect.TypeOf((*pref.ProtoMessage)(nil)).Elem()
|
||||
)
|
||||
|
||||
func newConverter(t reflect.Type, k pref.Kind) (conv pvalue.Converter, isLegacy 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 legacyWrapEnum(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 legacyWrapMessage(reflect.New(t.Elem())).ProtoReflect()
|
||||
},
|
||||
}, true
|
||||
}
|
||||
}
|
||||
return pvalue.NewConverter(t, k), false
|
||||
}
|
||||
|
||||
// defaultValueOf returns the default value for the field.
|
||||
func defaultValueOf(fd pref.FieldDescriptor) pref.Value {
|
||||
if fd == nil {
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/protobuf/internal/pragma"
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
@ -66,8 +65,8 @@ type MessageState struct {
|
||||
type messageState MessageState
|
||||
|
||||
var (
|
||||
_ pref.Message = (*messageState)(nil)
|
||||
_ pvalue.Unwrapper = (*messageState)(nil)
|
||||
_ pref.Message = (*messageState)(nil)
|
||||
_ Unwrapper = (*messageState)(nil)
|
||||
)
|
||||
|
||||
// messageDataType is a tuple of a pointer to the message data and
|
||||
@ -86,9 +85,9 @@ type (
|
||||
|
||||
var (
|
||||
_ pref.Message = (*messageReflectWrapper)(nil)
|
||||
_ pvalue.Unwrapper = (*messageReflectWrapper)(nil)
|
||||
_ Unwrapper = (*messageReflectWrapper)(nil)
|
||||
_ pref.ProtoMessage = (*messageIfaceWrapper)(nil)
|
||||
_ pvalue.Unwrapper = (*messageIfaceWrapper)(nil)
|
||||
_ Unwrapper = (*messageIfaceWrapper)(nil)
|
||||
)
|
||||
|
||||
// MessageOf returns a reflective view over a message. The input must be a
|
||||
|
@ -5,63 +5,64 @@
|
||||
package mapsort_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/protobuf/internal/mapsort"
|
||||
"google.golang.org/protobuf/internal/value"
|
||||
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
func TestRange(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
mapv interface{}
|
||||
kind pref.Kind
|
||||
}{
|
||||
{
|
||||
mapv: &map[bool]int32{
|
||||
false: 0,
|
||||
true: 1,
|
||||
},
|
||||
kind: pref.BoolKind,
|
||||
m := (&testpb.TestAllTypes{
|
||||
MapBoolBool: map[bool]bool{
|
||||
false: false,
|
||||
true: true,
|
||||
},
|
||||
{
|
||||
mapv: &map[int32]int32{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
},
|
||||
kind: pref.Int32Kind,
|
||||
MapInt32Int32: map[int32]int32{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
},
|
||||
{
|
||||
mapv: &map[uint64]int32{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
},
|
||||
kind: pref.Uint64Kind,
|
||||
MapUint64Uint64: map[uint64]uint64{
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
},
|
||||
{
|
||||
mapv: &map[string]int32{
|
||||
"a": 0,
|
||||
"b": 1,
|
||||
"c": 2,
|
||||
},
|
||||
kind: pref.StringKind,
|
||||
MapStringString: map[string]string{
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
},
|
||||
} {
|
||||
rv := reflect.TypeOf(test.mapv).Elem()
|
||||
mapv := value.MapOf(test.mapv, value.NewConverter(rv.Key(), test.kind), value.NewConverter(rv.Elem(), pref.Int32Kind))
|
||||
}).ProtoReflect()
|
||||
m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
|
||||
mapv := v.Map()
|
||||
var got []pref.MapKey
|
||||
mapsort.Range(mapv, test.kind, func(key pref.MapKey, _ pref.Value) bool {
|
||||
mapsort.Range(mapv, fd.MapKey().Kind(), func(key pref.MapKey, _ pref.Value) bool {
|
||||
got = append(got, key)
|
||||
return true
|
||||
})
|
||||
for i, key := range got {
|
||||
if int64(i) != mapv.Get(key).Int() {
|
||||
t.Errorf("out of order range over map: %v", got)
|
||||
for wanti, key := range got {
|
||||
var goti int
|
||||
switch x := mapv.Get(key).Interface().(type) {
|
||||
case bool:
|
||||
if x {
|
||||
goti = 1
|
||||
}
|
||||
case int32:
|
||||
goti = int(x)
|
||||
case uint64:
|
||||
goti = int(x)
|
||||
case string:
|
||||
goti, _ = strconv.Atoi(x)
|
||||
default:
|
||||
t.Fatalf("unhandled map value type %T", x)
|
||||
}
|
||||
if wanti != goti {
|
||||
t.Errorf("out of order range over map field %v: %v", fd.FullName(), got)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
@ -1,160 +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 value provides functionality for wrapping Go values to implement
|
||||
// protoreflect values.
|
||||
package value
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
// Unwrapper unwraps the value to the underlying value.
|
||||
// This is implemented by List and Map.
|
||||
type Unwrapper interface {
|
||||
ProtoUnwrap() interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
boolType = reflect.TypeOf(bool(false))
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
stringType = reflect.TypeOf(string(""))
|
||||
bytesType = reflect.TypeOf([]byte(nil))
|
||||
|
||||
enumIfaceV2 = reflect.TypeOf((*pref.Enum)(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. 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 {
|
||||
switch k {
|
||||
case pref.BoolKind:
|
||||
if t.Kind() == reflect.Bool {
|
||||
return newScalarConverter(t, boolType)
|
||||
}
|
||||
case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
|
||||
if t.Kind() == reflect.Int32 {
|
||||
return newScalarConverter(t, int32Type)
|
||||
}
|
||||
case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
|
||||
if t.Kind() == reflect.Int64 {
|
||||
return newScalarConverter(t, int64Type)
|
||||
}
|
||||
case pref.Uint32Kind, pref.Fixed32Kind:
|
||||
if t.Kind() == reflect.Uint32 {
|
||||
return newScalarConverter(t, uint32Type)
|
||||
}
|
||||
case pref.Uint64Kind, pref.Fixed64Kind:
|
||||
if t.Kind() == reflect.Uint64 {
|
||||
return newScalarConverter(t, uint64Type)
|
||||
}
|
||||
case pref.FloatKind:
|
||||
if t.Kind() == reflect.Float32 {
|
||||
return newScalarConverter(t, float32Type)
|
||||
}
|
||||
case pref.DoubleKind:
|
||||
if t.Kind() == reflect.Float64 {
|
||||
return newScalarConverter(t, float64Type)
|
||||
}
|
||||
case pref.StringKind:
|
||||
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
|
||||
return newScalarConverter(t, stringType)
|
||||
}
|
||||
case pref.BytesKind:
|
||||
if t.Kind() == reflect.String || (t.Kind() == reflect.Slice && t.Elem() == byteType) {
|
||||
return newScalarConverter(t, bytesType)
|
||||
}
|
||||
case pref.EnumKind:
|
||||
// Handle enums, which must be a named int32 type.
|
||||
if t.Implements(enumIfaceV2) && t.Kind() == reflect.Int32 {
|
||||
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(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 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.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(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
|
||||
},
|
||||
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 newScalarConverter(goType, pbType reflect.Type) Converter {
|
||||
return Converter{
|
||||
PBValueOf: func(v reflect.Value) pref.Value {
|
||||
if v.Type() != goType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", v.Type(), goType))
|
||||
}
|
||||
if goType.Kind() == reflect.String && pbType.Kind() == reflect.Slice && v.Len() == 0 {
|
||||
return pref.ValueOf([]byte(nil)) // ensure empty string is []byte(nil)
|
||||
}
|
||||
return pref.ValueOf(v.Convert(pbType).Interface())
|
||||
},
|
||||
GoValueOf: func(v pref.Value) reflect.Value {
|
||||
rv := reflect.ValueOf(v.Interface())
|
||||
if rv.Type() != pbType {
|
||||
panic(fmt.Sprintf("invalid type: got %v, want %v", rv.Type(), pbType))
|
||||
}
|
||||
if pbType.Kind() == reflect.String && goType.Kind() == reflect.Slice && rv.Len() == 0 {
|
||||
return reflect.Zero(goType) // ensure empty string is []byte(nil)
|
||||
}
|
||||
return rv.Convert(goType)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
NewEnum func(pref.EnumNumber) pref.Enum
|
||||
NewMessage func() pref.Message
|
||||
}
|
@ -12,7 +12,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/descfmt"
|
||||
"google.golang.org/protobuf/internal/value"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
@ -109,250 +108,7 @@ 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)
|
||||
_ protoreflect.EnumType = (*Enum)(nil)
|
||||
_ protoreflect.MessageType = (*Message)(nil)
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user