mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-29 09:32:38 +00:00
d888139e7b
The internal/fileinit package is split apart into two packages: * internal/filedesc constructs descriptors from the raw proto. It is very similar to the previous internal/fileinit package. * internal/filetype wraps descriptors with Go type information Overview: * The internal/fileinit package will be deleted in a future CL. It is kept around since the v1 repo currently depends on it. * The internal/prototype package is deleted. All former usages of it are now using internal/filedesc instead. Most significantly, the reflect/protodesc package was almost entirely re-written. * The internal/impl package drops support for messages that do not have a Descriptor method (pre-2016). This removes a significant amount of technical debt. filedesc.Builder to parse raw descriptors. * The internal/encoding/defval package now handles enum values by name. Change-Id: I3957bcc8588a70470fd6c7de1122216b80615ab7 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/182360 Reviewed-by: Damien Neil <dneil@google.com>
122 lines
3.4 KiB
Go
122 lines
3.4 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package impl
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
|
|
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"
|
|
)
|
|
|
|
// legacyWrapEnum wraps v as a protoreflect.Enum,
|
|
// where v must be a int32 kind and not implement the v2 API already.
|
|
func legacyWrapEnum(v reflect.Value) pref.Enum {
|
|
et := legacyLoadEnumType(v.Type())
|
|
return et.New(pref.EnumNumber(v.Int()))
|
|
}
|
|
|
|
var legacyEnumTypeCache sync.Map // map[reflect.Type]protoreflect.EnumType
|
|
|
|
// legacyLoadEnumType dynamically loads a protoreflect.EnumType for t,
|
|
// where t must be an int32 kind and not implement the v2 API already.
|
|
func legacyLoadEnumType(t reflect.Type) pref.EnumType {
|
|
// Fast-path: check if a EnumType is cached for this concrete type.
|
|
if et, ok := legacyEnumTypeCache.Load(t); ok {
|
|
return et.(pref.EnumType)
|
|
}
|
|
|
|
// Slow-path: derive enum descriptor and initialize EnumType.
|
|
var et pref.EnumType
|
|
var m sync.Map // map[protoreflect.EnumNumber]proto.Enum
|
|
ed := LegacyLoadEnumDesc(t)
|
|
et = &prototype.Enum{
|
|
EnumDescriptor: ed,
|
|
NewEnum: func(n pref.EnumNumber) pref.Enum {
|
|
if e, ok := m.Load(n); ok {
|
|
return e.(pref.Enum)
|
|
}
|
|
e := &legacyEnumWrapper{num: n, pbTyp: et, goTyp: t}
|
|
m.Store(n, e)
|
|
return e
|
|
},
|
|
}
|
|
if et, ok := legacyEnumTypeCache.LoadOrStore(t, et); ok {
|
|
return et.(pref.EnumType)
|
|
}
|
|
return et
|
|
}
|
|
|
|
type legacyEnumWrapper struct {
|
|
num pref.EnumNumber
|
|
pbTyp pref.EnumType
|
|
goTyp reflect.Type
|
|
}
|
|
|
|
func (e *legacyEnumWrapper) Descriptor() pref.EnumDescriptor {
|
|
return e.pbTyp.Descriptor()
|
|
}
|
|
func (e *legacyEnumWrapper) Number() pref.EnumNumber {
|
|
return e.num
|
|
}
|
|
func (e *legacyEnumWrapper) ProtoReflect() pref.Enum {
|
|
return e
|
|
}
|
|
func (e *legacyEnumWrapper) ProtoUnwrap() interface{} {
|
|
v := reflect.New(e.goTyp).Elem()
|
|
v.SetInt(int64(e.num))
|
|
return v.Interface()
|
|
}
|
|
|
|
var (
|
|
_ pref.Enum = (*legacyEnumWrapper)(nil)
|
|
_ pvalue.Unwrapper = (*legacyEnumWrapper)(nil)
|
|
)
|
|
|
|
var legacyEnumDescCache sync.Map // map[reflect.Type]protoreflect.EnumDescriptor
|
|
|
|
var legacyEnumNumberType = reflect.TypeOf(pref.EnumNumber(0))
|
|
|
|
// LegacyLoadEnumDesc returns an EnumDescriptor derived from the Go type,
|
|
// which must be an int32 kind and not implement the v2 API already.
|
|
//
|
|
// This is exported for testing purposes.
|
|
func LegacyLoadEnumDesc(t reflect.Type) pref.EnumDescriptor {
|
|
// Fast-path: check if an EnumDescriptor is cached for this concrete type.
|
|
if ed, ok := legacyEnumDescCache.Load(t); ok {
|
|
return ed.(pref.EnumDescriptor)
|
|
}
|
|
|
|
// Slow-path: initialize EnumDescriptor from the raw descriptor.
|
|
ev := reflect.Zero(t).Interface()
|
|
if _, ok := ev.(pref.Enum); ok {
|
|
panic(fmt.Sprintf("%v already implements proto.Enum", t))
|
|
}
|
|
edV1, ok := ev.(enumV1)
|
|
if !ok {
|
|
panic(fmt.Sprintf("enum %v is no longer supported; please regenerate", t))
|
|
}
|
|
b, idxs := edV1.EnumDescriptor()
|
|
|
|
var ed pref.EnumDescriptor
|
|
if len(idxs) == 1 {
|
|
ed = legacyLoadFileDesc(b).Enums().Get(idxs[0])
|
|
} else {
|
|
md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
|
|
for _, i := range idxs[1 : len(idxs)-1] {
|
|
md = md.Messages().Get(i)
|
|
}
|
|
ed = md.Enums().Get(idxs[len(idxs)-1])
|
|
}
|
|
if ed, ok := legacyEnumDescCache.LoadOrStore(t, ed); ok {
|
|
return ed.(protoreflect.EnumDescriptor)
|
|
}
|
|
return ed
|
|
}
|