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/proto/encode.go b/proto/encode.go
index 255d0a3..96d6799 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -176,25 +176,52 @@
 	}
 }
 
-func (o MarshalOptions) marshalField(b []byte, field protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
-	num := field.Number()
-	kind := field.Kind()
+func (o MarshalOptions) marshalField(b []byte, fd protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
+	num := fd.Number()
+	kind := fd.Kind()
 	switch {
-	case field.Cardinality() != protoreflect.Repeated:
-		b = wire.AppendTag(b, num, wireTypes[kind])
-		return o.marshalSingular(b, num, field, value)
-	case field.IsMap():
-		return o.marshalMap(b, num, kind, field.Message(), value.Map())
-	case field.IsPacked():
-		return o.marshalPacked(b, num, field, value.List())
+	case fd.IsList():
+		return o.marshalList(b, num, fd, value.List())
+	case fd.IsMap():
+		return o.marshalMap(b, num, fd, value.Map())
 	default:
-		return o.marshalList(b, num, field, value.List())
+		b = wire.AppendTag(b, num, wireTypes[kind])
+		return o.marshalSingular(b, num, fd, value)
 	}
 }
 
-func (o MarshalOptions) marshalMap(b []byte, num wire.Number, kind protoreflect.Kind, mdesc protoreflect.MessageDescriptor, mapv protoreflect.Map) ([]byte, error) {
-	keyf := mdesc.Fields().ByNumber(1)
-	valf := mdesc.Fields().ByNumber(2)
+func (o MarshalOptions) marshalList(b []byte, num wire.Number, fd protoreflect.FieldDescriptor, list protoreflect.List) ([]byte, error) {
+	if fd.IsPacked() {
+		b = wire.AppendTag(b, num, wire.BytesType)
+		b, pos := appendSpeculativeLength(b)
+		var nerr errors.NonFatal
+		for i, llen := 0, list.Len(); i < llen; i++ {
+			var err error
+			b, err = o.marshalSingular(b, num, fd, list.Get(i))
+			if !nerr.Merge(err) {
+				return b, err
+			}
+		}
+		b = finishSpeculativeLength(b, pos)
+		return b, nerr.E
+	}
+
+	kind := fd.Kind()
+	var nerr errors.NonFatal
+	for i, llen := 0, list.Len(); i < llen; i++ {
+		var err error
+		b = wire.AppendTag(b, num, wireTypes[kind])
+		b, err = o.marshalSingular(b, num, fd, list.Get(i))
+		if !nerr.Merge(err) {
+			return b, err
+		}
+	}
+	return b, nerr.E
+}
+
+func (o MarshalOptions) marshalMap(b []byte, num wire.Number, fd protoreflect.FieldDescriptor, mapv protoreflect.Map) ([]byte, error) {
+	keyf := fd.MapKey()
+	valf := fd.MapValue()
 	var nerr errors.NonFatal
 	var err error
 	o.rangeMap(mapv, keyf.Kind(), func(key protoreflect.MapKey, value protoreflect.Value) bool {
@@ -229,35 +256,6 @@
 	mapsort.Range(mapv, kind, f)
 }
 
-func (o MarshalOptions) marshalPacked(b []byte, num wire.Number, field protoreflect.FieldDescriptor, list protoreflect.List) ([]byte, error) {
-	b = wire.AppendTag(b, num, wire.BytesType)
-	b, pos := appendSpeculativeLength(b)
-	var nerr errors.NonFatal
-	for i, llen := 0, list.Len(); i < llen; i++ {
-		var err error
-		b, err = o.marshalSingular(b, num, field, list.Get(i))
-		if !nerr.Merge(err) {
-			return b, err
-		}
-	}
-	b = finishSpeculativeLength(b, pos)
-	return b, nerr.E
-}
-
-func (o MarshalOptions) marshalList(b []byte, num wire.Number, field protoreflect.FieldDescriptor, list protoreflect.List) ([]byte, error) {
-	kind := field.Kind()
-	var nerr errors.NonFatal
-	for i, llen := 0, list.Len(); i < llen; i++ {
-		var err error
-		b = wire.AppendTag(b, num, wireTypes[kind])
-		b, err = o.marshalSingular(b, num, field, list.Get(i))
-		if !nerr.Merge(err) {
-			return b, err
-		}
-	}
-	return b, nerr.E
-}
-
 // When encoding length-prefixed fields, we speculatively set aside some number of bytes
 // for the length, encode the data, and then encode the length (shifting the data if necessary
 // to make room).