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>
diff --git a/internal/legacy/export.go b/internal/legacy/export.go
index ec87a68..701b578 100644
--- a/internal/legacy/export.go
+++ b/internal/legacy/export.go
@@ -5,6 +5,7 @@
package legacy
import (
+ "fmt"
"reflect"
pimpl "google.golang.org/protobuf/internal/impl"
@@ -17,8 +18,8 @@
// 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 @@
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 @@
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{})
}