internal/impl: store extension values as Values

Change the storage type of ExtensionField from interface{} to
protoreflect.Value.

Replace the codec functions operating on interface{}s with ones
operating on Values.

Values are potentially more efficient, since they can represent
non-pointer types without allocation. This also reduces the number of
types used to represent field values.

Additionally, this change lays groundwork for changing the
user-visible representation of repeated extension fields from
*[]T to []T. The storage type for extension fields must support mutation
(thus *[]T currently); changing the storage type to a Value permits this
without the need to introduce yet another view on field values.

Change-Id: Ida336be14112bb940f655236eb58df21bf312525
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/192218
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/codec_reflect.go b/internal/impl/codec_reflect.go
index b83a3b3..5884ee4 100644
--- a/internal/impl/codec_reflect.go
+++ b/internal/impl/codec_reflect.go
@@ -87,15 +87,52 @@
 }
 
 func sizeEnumSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
-	return sizeEnumSliceReflect(p.v.Elem(), tagsize, opts)
+	s := p.v.Elem()
+	for i, llen := 0, s.Len(); i < llen; i++ {
+		size += wire.SizeVarint(uint64(s.Index(i).Int())) + tagsize
+	}
+	return size
 }
 
 func appendEnumSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	return appendEnumSliceReflect(b, p.v.Elem(), wiretag, opts)
+	s := p.v.Elem()
+	for i, llen := 0, s.Len(); i < llen; i++ {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
+	}
+	return b, nil
 }
 
 func consumeEnumSlice(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (n int, err error) {
-	return consumeEnumSliceReflect(b, p.v, wtyp, opts)
+	s := p.v.Elem()
+	if wtyp == wire.BytesType {
+		b, n = wire.ConsumeBytes(b)
+		if n < 0 {
+			return 0, wire.ParseError(n)
+		}
+		for len(b) > 0 {
+			v, n := wire.ConsumeVarint(b)
+			if n < 0 {
+				return 0, wire.ParseError(n)
+			}
+			rv := reflect.New(s.Type().Elem()).Elem()
+			rv.SetInt(int64(v))
+			s.Set(reflect.Append(s, rv))
+			b = b[n:]
+		}
+		return n, nil
+	}
+	if wtyp != wire.VarintType {
+		return 0, errUnknown
+	}
+	v, n := wire.ConsumeVarint(b)
+	if n < 0 {
+		return 0, wire.ParseError(n)
+	}
+	rv := reflect.New(s.Type().Elem()).Elem()
+	rv.SetInt(int64(v))
+	s.Set(reflect.Append(s, rv))
+	return n, nil
 }
 
 var coderEnumSlice = pointerCoderFuncs{
@@ -105,11 +142,34 @@
 }
 
 func sizeEnumPackedSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
-	return sizeEnumPackedSliceReflect(p.v.Elem(), tagsize, opts)
+	s := p.v.Elem()
+	llen := s.Len()
+	if llen == 0 {
+		return 0
+	}
+	n := 0
+	for i := 0; i < llen; i++ {
+		n += wire.SizeVarint(uint64(s.Index(i).Int()))
+	}
+	return tagsize + wire.SizeBytes(n)
 }
 
 func appendEnumPackedSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
-	return appendEnumPackedSliceReflect(b, p.v.Elem(), wiretag, opts)
+	s := p.v.Elem()
+	llen := s.Len()
+	if llen == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for i := 0; i < llen; i++ {
+		n += wire.SizeVarint(uint64(s.Index(i).Int()))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for i := 0; i < llen; i++ {
+		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
+	}
+	return b, nil
 }
 
 var coderEnumPackedSlice = pointerCoderFuncs{