all: do best-effort initialization check on fast path unmarshal

Add a fast check for required fields to the fast path unmarshal.
This is best-effort and will fail to detect some initialized
messages: Messages with more than 64 required fields, messages
split across multiple tags, possibly other cases.

In the cases where it works (which is most of them in practice),
this permits us to skip the IsInitialized check.

Change-Id: I6b70953a333033a5e64fb7ca37a59786cb0f75a0
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/215878
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/internal/impl/codec_field.go b/internal/impl/codec_field.go
index f1f0671..433dacb 100644
--- a/internal/impl/codec_field.go
+++ b/internal/impl/codec_field.go
@@ -13,6 +13,7 @@
 	"google.golang.org/protobuf/proto"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	preg "google.golang.org/protobuf/reflect/protoregistry"
+	piface "google.golang.org/protobuf/runtime/protoiface"
 )
 
 type errInvalidUTF8 struct{}
@@ -227,10 +228,12 @@
 	if p.Elem().IsNil() {
 		p.SetPointer(pointerOfValue(reflect.New(mi.GoReflectType.Elem())))
 	}
-	if _, err := mi.unmarshalPointer(v, p.Elem(), 0, opts); err != nil {
+	o, err := mi.unmarshalPointer(v, p.Elem(), 0, opts)
+	if err != nil {
 		return out, err
 	}
 	out.n = n
+	out.initialized = o.initialized
 	return out, nil
 }
 
@@ -252,10 +255,14 @@
 	if n < 0 {
 		return out, wire.ParseError(n)
 	}
-	if err := opts.Options().Unmarshal(v, m); err != nil {
+	o, err := opts.Options().UnmarshalState(m, piface.UnmarshalInput{
+		Buf: v,
+	})
+	if err != nil {
 		return out, err
 	}
 	out.n = n
+	out.initialized = o.Initialized
 	return out, nil
 }
 
@@ -395,8 +402,15 @@
 	if n < 0 {
 		return out, wire.ParseError(n)
 	}
+	o, err := opts.Options().UnmarshalState(m, piface.UnmarshalInput{
+		Buf: b,
+	})
+	if err != nil {
+		return out, err
+	}
 	out.n = n
-	return out, opts.Options().Unmarshal(b, m)
+	out.initialized = o.Initialized
+	return out, nil
 }
 
 func makeMessageSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
@@ -469,11 +483,13 @@
 	}
 	m := reflect.New(mi.GoReflectType.Elem()).Interface()
 	mp := pointerOfIface(m)
-	if _, err := mi.unmarshalPointer(v, mp, 0, opts); err != nil {
+	o, err := mi.unmarshalPointer(v, mp, 0, opts)
+	if err != nil {
 		return out, err
 	}
 	p.AppendPointerSlice(mp)
 	out.n = n
+	out.initialized = o.initialized
 	return out, nil
 }
 
@@ -522,11 +538,15 @@
 		return out, wire.ParseError(n)
 	}
 	mp := reflect.New(goType.Elem())
-	if err := opts.Options().Unmarshal(v, asMessage(mp)); err != nil {
+	o, err := opts.Options().UnmarshalState(asMessage(mp), piface.UnmarshalInput{
+		Buf: v,
+	})
+	if err != nil {
 		return out, err
 	}
 	p.AppendPointerSlice(pointerOfValue(mp))
 	out.n = n
+	out.initialized = o.Initialized
 	return out, nil
 }
 
@@ -580,11 +600,15 @@
 		return pref.Value{}, out, wire.ParseError(n)
 	}
 	m := list.NewElement()
-	if err := opts.Options().Unmarshal(v, m.Message().Interface()); err != nil {
+	o, err := opts.Options().UnmarshalState(m.Message().Interface(), piface.UnmarshalInput{
+		Buf: v,
+	})
+	if err != nil {
 		return pref.Value{}, out, err
 	}
 	list.Append(m)
 	out.n = n
+	out.initialized = o.Initialized
 	return listv, out, nil
 }
 
@@ -642,11 +666,15 @@
 		return pref.Value{}, out, wire.ParseError(n)
 	}
 	m := list.NewElement()
-	if err := opts.Options().Unmarshal(b, m.Message().Interface()); err != nil {
+	o, err := opts.Options().UnmarshalState(m.Message().Interface(), piface.UnmarshalInput{
+		Buf: b,
+	})
+	if err != nil {
 		return pref.Value{}, out, err
 	}
 	list.Append(m)
 	out.n = n
+	out.initialized = o.Initialized
 	return listv, out, nil
 }
 
@@ -728,11 +756,15 @@
 		return out, wire.ParseError(n)
 	}
 	mp := reflect.New(goType.Elem())
-	if err := opts.Options().Unmarshal(b, asMessage(mp)); err != nil {
+	o, err := opts.Options().UnmarshalState(asMessage(mp), piface.UnmarshalInput{
+		Buf: b,
+	})
+	if err != nil {
 		return out, err
 	}
 	p.AppendPointerSlice(pointerOfValue(mp))
 	out.n = n
+	out.initialized = o.Initialized
 	return out, nil
 }