reflect/protoreflect: add helper methods to FieldDescriptor

Added API:
	FieldDescriptor.IsExtension
	FieldDescriptor.IsList
	FieldDescriptor.MapKey
	FieldDescriptor.MapValue
	FieldDescriptor.ContainingOneof
	FieldDescriptor.ContainingMessage

Deprecated API (to be removed in subsequent CL):
	FieldDescriptor.Oneof
	FieldDescriptor.Extendee

These methods help cleanup several common usage patterns.

Change-Id: I9a3ffabc2edb2173c536509b22f330f98bba7cf3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/176977
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/encoding/textpb/decode.go b/encoding/textpb/decode.go
index 38092ac..c586331 100644
--- a/encoding/textpb/decode.go
+++ b/encoding/textpb/decode.go
@@ -159,14 +159,36 @@
 			return errors.New("%v contains unknown field: %v", messageDesc.FullName(), tkey)
 		}
 
-		if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
-			// Map or list fields have cardinality of repeated.
-			if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
+		switch {
+		case fd.IsList():
+			// If input is not a list, turn it into a list.
+			var items []text.Value
+			if tval.Type() != text.List {
+				items = []text.Value{tval}
+			} else {
+				items = tval.List()
+			}
+
+			list := knownFields.Get(fd.Number()).List()
+			if err := o.unmarshalList(items, fd, list); !nerr.Merge(err) {
 				return err
 			}
-		} else {
+		case fd.IsMap():
+			// If input is not a list, turn it into a list.
+			var items []text.Value
+			if tval.Type() != text.List {
+				items = []text.Value{tval}
+			} else {
+				items = tval.List()
+			}
+
+			mmap := knownFields.Get(fd.Number()).Map()
+			if err := o.unmarshalMap(items, fd, mmap); !nerr.Merge(err) {
+				return err
+			}
+		default:
 			// If field is a oneof, check if it has already been set.
-			if od := fd.Oneof(); od != nil {
+			if od := fd.ContainingOneof(); od != nil {
 				idx := uint64(od.Index())
 				if seenOneofs.Has(idx) {
 					return errors.New("oneof %v is already set", od.FullName())
@@ -232,33 +254,6 @@
 	return nerr.E
 }
 
-// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
-// call this for cardinality=repeated.
-func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
-	var items []text.Value
-	// If input is not a list, turn it into a list.
-	if input.Type() != text.List {
-		items = []text.Value{input}
-	} else {
-		items = input.List()
-	}
-
-	var nerr errors.NonFatal
-	num := fd.Number()
-	val := knownFields.Get(num)
-	if !fd.IsMap() {
-		if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
-			return err
-		}
-	} else {
-		if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
-			return err
-		}
-	}
-
-	return nerr.E
-}
-
 // unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
 // the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
 func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
@@ -358,14 +353,11 @@
 // unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
 func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
 	var nerr errors.NonFatal
-	fields := fd.Message().Fields()
-	keyDesc := fields.ByNumber(1)
-	valDesc := fields.ByNumber(2)
 
 	// Determine ahead whether map entry is a scalar type or a message type in order to call the
 	// appropriate unmarshalMapValue func inside the for loop below.
 	unmarshalMapValue := unmarshalMapScalarValue
-	switch valDesc.Kind() {
+	switch fd.MapValue().Kind() {
 	case pref.MessageKind, pref.GroupKind:
 		unmarshalMapValue = o.unmarshalMapMessageValue
 	}
@@ -378,11 +370,11 @@
 		if !nerr.Merge(err) {
 			return err
 		}
-		pkey, err := unmarshalMapKey(tkey, keyDesc)
+		pkey, err := unmarshalMapKey(tkey, fd.MapKey())
 		if !nerr.Merge(err) {
 			return err
 		}
-		err = unmarshalMapValue(tval, pkey, valDesc, mmap)
+		err = unmarshalMapValue(tval, pkey, fd.MapValue(), mmap)
 		if !nerr.Merge(err) {
 			return err
 		}
diff --git a/encoding/textpb/encode.go b/encoding/textpb/encode.go
index b8b2e71..9bd8279 100644
--- a/encoding/textpb/encode.go
+++ b/encoding/textpb/encode.go
@@ -132,28 +132,26 @@
 func (o MarshalOptions) appendField(msgFields [][2]text.Value, name text.Value, pval pref.Value, fd pref.FieldDescriptor) ([][2]text.Value, error) {
 	var nerr errors.NonFatal
 
-	if fd.Cardinality() == pref.Repeated {
-		// Map or repeated fields.
-		var items []text.Value
-		var err error
-		if fd.IsMap() {
-			items, err = o.marshalMap(pval.Map(), fd)
-			if !nerr.Merge(err) {
-				return msgFields, err
-			}
-		} else {
-			items, err = o.marshalList(pval.List(), fd)
-			if !nerr.Merge(err) {
-				return msgFields, err
-			}
+	switch {
+	case fd.IsList():
+		items, err := o.marshalList(pval.List(), fd)
+		if !nerr.Merge(err) {
+			return msgFields, err
 		}
 
-		// Add each item as key: value field.
 		for _, item := range items {
 			msgFields = append(msgFields, [2]text.Value{name, item})
 		}
-	} else {
-		// Required or optional fields.
+	case fd.IsMap():
+		items, err := o.marshalMap(pval.Map(), fd)
+		if !nerr.Merge(err) {
+			return msgFields, err
+		}
+
+		for _, item := range items {
+			msgFields = append(msgFields, [2]text.Value{name, item})
+		}
+	default:
 		tval, err := o.marshalSingular(pval, fd)
 		if !nerr.Merge(err) {
 			return msgFields, err
@@ -231,19 +229,16 @@
 	var nerr errors.NonFatal
 	// values is a list of messages.
 	values := make([]text.Value, 0, mmap.Len())
-	msgFields := fd.Message().Fields()
-	keyType := msgFields.ByNumber(1)
-	valType := msgFields.ByNumber(2)
 
 	var err error
-	mapsort.Range(mmap, keyType.Kind(), func(key pref.MapKey, val pref.Value) bool {
+	mapsort.Range(mmap, fd.MapKey().Kind(), func(key pref.MapKey, val pref.Value) bool {
 		var keyTxtVal text.Value
-		keyTxtVal, err = o.marshalSingular(key.Value(), keyType)
+		keyTxtVal, err = o.marshalSingular(key.Value(), fd.MapKey())
 		if !nerr.Merge(err) {
 			return false
 		}
 		var valTxtVal text.Value
-		valTxtVal, err = o.marshalSingular(val, valType)
+		valTxtVal, err = o.marshalSingular(val, fd.MapValue())
 		if !nerr.Merge(err) {
 			return false
 		}
@@ -314,7 +309,7 @@
 	if xd.FullName().Parent() != md.FullName() {
 		return false
 	}
-	xmd, ok := xd.Extendee().(interface{ IsMessageSet() bool })
+	xmd, ok := xd.ContainingMessage().(interface{ IsMessageSet() bool })
 	return ok && xmd.IsMessageSet()
 }