internal/impl: add fast-path unmarshal

Benchmarks run with:
  go test ./benchmarks/ -bench=Wire  -benchtime=500ms -benchmem -count=8

Fast-path vs. parent commit:

  name                                      old time/op    new time/op    delta
  Wire/Unmarshal/google_message1_proto2-12    1.35µs ± 2%    0.45µs ± 4%  -67.01%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message1_proto3-12    1.07µs ± 1%    0.31µs ± 1%  -71.04%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message2-12            691µs ± 2%     188µs ± 2%  -72.78%  (p=0.000 n=7+8)

  name                                      old allocs/op  new allocs/op  delta
  Wire/Unmarshal/google_message1_proto2-12      60.0 ± 0%      25.0 ± 0%  -58.33%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message1_proto3-12      42.0 ± 0%       7.0 ± 0%  -83.33%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message2-12            28.6k ± 0%      8.5k ± 0%  -70.34%  (p=0.000 n=8+8)

Fast-path vs. -v1:

  name                                      old time/op    new time/op    delta
  Wire/Unmarshal/google_message1_proto2-12     702ns ± 1%     445ns ± 4%   -36.58%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message1_proto3-12     604ns ± 1%     311ns ± 1%   -48.54%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message2-12            179µs ± 3%     188µs ± 2%    +5.30%  (p=0.000 n=7+8)

  name                                      old allocs/op  new allocs/op  delta
  Wire/Unmarshal/google_message1_proto2-12      26.0 ± 0%      25.0 ± 0%    -3.85%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message1_proto3-12      8.00 ± 0%      7.00 ± 0%   -12.50%  (p=0.000 n=8+8)
  Wire/Unmarshal/google_message2-12            8.49k ± 0%     8.49k ± 0%    -0.01%  (p=0.000 n=8+8)

Change-Id: I6247ac3fd66a63d9acb902cbd192094ee3d151c3
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/185147
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/impl/codec_reflect.go b/internal/impl/codec_reflect.go
index 05ceb33..d307efe 100644
--- a/internal/impl/codec_reflect.go
+++ b/internal/impl/codec_reflect.go
@@ -7,6 +7,8 @@
 package impl
 
 import (
+	"reflect"
+
 	"google.golang.org/protobuf/internal/encoding/wire"
 )
 
@@ -22,9 +24,22 @@
 	return b, nil
 }
 
+func consumeEnum(b []byte, p pointer, wtyp wire.Type, _ unmarshalOptions) (n int, err error) {
+	if wtyp != wire.VarintType {
+		return 0, errUnknown
+	}
+	v, n := wire.ConsumeVarint(b)
+	if n < 0 {
+		return 0, wire.ParseError(n)
+	}
+	p.v.Elem().SetInt(int64(v))
+	return n, nil
+}
+
 var coderEnum = pointerCoderFuncs{
-	size:    sizeEnum,
-	marshal: appendEnum,
+	size:      sizeEnum,
+	marshal:   appendEnum,
+	unmarshal: consumeEnum,
 }
 
 func sizeEnumNoZero(p pointer, tagsize int, opts marshalOptions) (size int) {
@@ -42,8 +57,9 @@
 }
 
 var coderEnumNoZero = pointerCoderFuncs{
-	size:    sizeEnumNoZero,
-	marshal: appendEnumNoZero,
+	size:      sizeEnumNoZero,
+	marshal:   appendEnumNoZero,
+	unmarshal: consumeEnum,
 }
 
 func sizeEnumPtr(p pointer, tagsize int, opts marshalOptions) (size int) {
@@ -54,9 +70,20 @@
 	return appendEnum(b, pointer{p.v.Elem()}, wiretag, opts)
 }
 
+func consumeEnumPtr(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (n int, err error) {
+	if wtyp != wire.VarintType {
+		return 0, errUnknown
+	}
+	if p.v.Elem().IsNil() {
+		p.v.Elem().Set(reflect.New(p.v.Elem().Type().Elem()))
+	}
+	return consumeEnum(b, pointer{p.v.Elem()}, wtyp, opts)
+}
+
 var coderEnumPtr = pointerCoderFuncs{
-	size:    sizeEnumPtr,
-	marshal: appendEnumPtr,
+	size:      sizeEnumPtr,
+	marshal:   appendEnumPtr,
+	unmarshal: consumeEnumPtr,
 }
 
 func sizeEnumSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
@@ -67,9 +94,14 @@
 	return appendEnumSliceReflect(b, p.v.Elem(), wiretag, opts)
 }
 
+func consumeEnumSlice(b []byte, p pointer, wtyp wire.Type, opts unmarshalOptions) (n int, err error) {
+	return consumeEnumSliceReflect(b, p.v, wtyp, opts)
+}
+
 var coderEnumSlice = pointerCoderFuncs{
-	size:    sizeEnumSlice,
-	marshal: appendEnumSlice,
+	size:      sizeEnumSlice,
+	marshal:   appendEnumSlice,
+	unmarshal: consumeEnumSlice,
 }
 
 func sizeEnumPackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
@@ -104,6 +136,7 @@
 }
 
 var coderEnumPackedSlice = pointerCoderFuncs{
-	size:    sizeEnumPackedSlice,
-	marshal: appendEnumPackedSlice,
+	size:      sizeEnumPackedSlice,
+	marshal:   appendEnumPackedSlice,
+	unmarshal: consumeEnumSlice,
 }