reflect/protoreflect: add Descriptor specific methods
Added methods:
Enum.Descriptor
Message.Descriptor
EnumType.Descriptor
MessageType.Descriptor
ExtensionType.Descriptor
Message.New
All functionality is switched over to use those methods instead of
implicitly relying on the fact that {Enum,Message}Type implicitly
implement the associated descriptor interface.
This CL does not yet remove {Enum,Message}.Type or prevent
{Enum,Message,Extension}Type from implementating a descriptor.
That is a subsequent CL.
The Message.New method is also added to replace functionality
that will be lost when the Type methods are removed.
Change-Id: I7fefde1673bbd40bfdac489aca05cec9a6c98eb1
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/174918
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/impl/export.go b/internal/impl/export.go
index 5dae010..0b53d78 100644
--- a/internal/impl/export.go
+++ b/internal/impl/export.go
@@ -5,10 +5,10 @@
package impl
import (
+ "reflect"
"strconv"
"github.com/golang/protobuf/v2/encoding/textpb"
- ptype "github.com/golang/protobuf/v2/internal/prototype"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
@@ -16,11 +16,12 @@
// functions that we do not want to appear in godoc.
type Export struct{}
+// enum is any enum type generated by protoc-gen-go
+// and must be a named int32 type.
+type enum = interface{}
+
// EnumOf returns the protoreflect.Enum interface over e.
-// If e already implements proto.Enum, then it directly calls the
-// ProtoReflect method, otherwise it wraps the v1 enum to implement
-// the v2 reflective interface.
-func (Export) EnumOf(e interface{}) pref.Enum {
+func (Export) EnumOf(e enum) pref.Enum {
if ev, ok := e.(pref.Enum); ok {
return ev
}
@@ -28,16 +29,34 @@
}
// EnumTypeOf returns the protoreflect.EnumType for e.
-// If e already implements proto.Enum, then it obtains the type by directly
-// calling the ProtoReflect.Type method, otherwise it derives an enum type
-// from the v1 named int32 type.
-func (Export) EnumTypeOf(e interface{}) pref.EnumType {
+func (Export) EnumTypeOf(e enum) pref.EnumType {
if ev, ok := e.(pref.Enum); ok {
- return ev.Type()
+ return &enumType{ev.Descriptor(), reflect.TypeOf(e)}
}
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 {
+ return ev.Descriptor()
+ }
+ return legacyWrapper.EnumDescriptorOf(e)
+}
+
// EnumStringOf returns the enum value as a string, either as the name if
// the number is resolvable, or the number formatted as a string.
func (Export) EnumStringOf(ed pref.EnumDescriptor, n pref.EnumNumber) string {
@@ -48,11 +67,12 @@
return strconv.Itoa(int(n))
}
+// message is any message type generated by protoc-gen-go
+// and must be a pointer to a named struct type.
+type message = interface{}
+
// MessageOf returns the protoreflect.Message interface over m.
-// If m already implements proto.Message, then it directly calls the
-// ProtoReflect method, otherwise it wraps the v1 message to implement
-// the v2 reflective interface.
-func (Export) MessageOf(m interface{}) pref.Message {
+func (Export) MessageOf(m message) pref.Message {
if mv, ok := m.(pref.ProtoMessage); ok {
return mv.ProtoReflect()
}
@@ -60,32 +80,32 @@
}
// MessageTypeOf returns the protoreflect.MessageType for m.
-// If m already implements proto.Message, then it obtains the type by directly
-// calling the ProtoReflect.Type method, otherwise it derives a message type
-// from the v1 message struct.
-func (Export) MessageTypeOf(m interface{}) pref.MessageType {
+func (Export) MessageTypeOf(m message) pref.MessageType {
if mv, ok := m.(pref.ProtoMessage); ok {
- return mv.ProtoReflect().Type()
+ return &messageType{mv.ProtoReflect().Descriptor(), reflect.TypeOf(m)}
}
return legacyWrapper.MessageTypeOf(m)
}
-// ExtensionTypeOf returns a protoreflect.ExtensionType where the type of the
-// field is t. The type t must be provided if the field is an enum or message.
-// If t already implements proto.Enum or proto.Message, then this returns
-// an extension type by directly calling prototype.GoExtension.
-// Otherwise, it derives an extension type by wrapping the enum or message
-// using EnumOf or MessageOf.
-func (Export) ExtensionTypeOf(d pref.ExtensionDescriptor, t interface{}) pref.ExtensionType {
- switch t := t.(type) {
- case nil:
- return ptype.GoExtension(d, nil, nil)
- case pref.Enum:
- return ptype.GoExtension(d, t.Type(), nil)
- case pref.ProtoMessage:
- return ptype.GoExtension(d, nil, t.ProtoReflect().Type())
+// 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 {
+ return mv.ProtoReflect().Descriptor()
}
- return legacyWrapper.ExtensionTypeOf(d, t)
+ return legacyWrapper.MessageDescriptorOf(m)
}
// MessageStringOf returns the message value as a string,