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/value/convert.go b/internal/value/convert.go
index 35de822..eb8d570 100644
--- a/internal/value/convert.go
+++ b/internal/value/convert.go
@@ -11,7 +11,6 @@
 	"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 @@
 	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 @@
 				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 @@
 	}
 }
 
-// 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
 }
diff --git a/internal/value/list.go b/internal/value/list.go
index f40a73f..5181f4f 100644
--- a/internal/value/list.go
+++ b/internal/value/list.go
@@ -43,7 +43,7 @@
 	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()
diff --git a/internal/value/map.go b/internal/value/map.go
index 3461d2e..9fc7358 100644
--- a/internal/value/map.go
+++ b/internal/value/map.go
@@ -77,7 +77,7 @@
 	}
 }
 func (ms mapReflect) NewMessage() pref.Message {
-	return ms.valConv.MessageType.New()
+	return ms.valConv.NewMessage()
 }
 func (ms mapReflect) ProtoUnwrap() interface{} {
 	return ms.v.Interface()