internal/impl: refactor validation a bit

Return the size of the field read from the validator, permitting us to
avoid an extra parse when skipping over groups.

Return an UnmarshalOutput from the validator, since it already combines
two of the validator outputs: bytes read and initialization status.

Remove initialization status from the ValidationStatus enum, since it's
covered by the UnmarshalOutput.

Change-Id: I3e684c45d15aa1992d8dc3bde0f608880d34a94b
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/217763
Reviewed-by: Joe Tsai <joetsai@google.com>
diff --git a/proto/testmessages_test.go b/proto/testmessages_test.go
index d980fd1..3847c21 100644
--- a/proto/testmessages_test.go
+++ b/proto/testmessages_test.go
@@ -28,6 +28,7 @@
 	checkFastInit    bool
 	unmarshalOptions proto.UnmarshalOptions
 	validationStatus impl.ValidationStatus
+	nocheckValidInit bool
 }
 
 func makeMessages(in protobuild.Message, messages ...proto.Message) []proto.Message {
@@ -1045,8 +1046,9 @@
 		}.Marshal(),
 	},
 	{
-		desc:          "required field in optional message set (split across multiple tags)",
-		checkFastInit: false, // fast init checks don't handle split messages
+		desc:             "required field in optional message set (split across multiple tags)",
+		checkFastInit:    false, // fast init checks don't handle split messages
+		nocheckValidInit: true,  // validation doesn't either
 		decodeTo: makeMessages(protobuild.Message{
 			"optional_message": protobuild.Message{
 				"required_field": 1,
@@ -1058,7 +1060,6 @@
 				pack.Tag{1, pack.VarintType}, pack.Varint(1),
 			}),
 		}.Marshal(),
-		validationStatus: impl.ValidationValidMaybeUninitalized,
 	},
 	{
 		desc:          "required field in repeated message unset",
diff --git a/proto/validate_test.go b/proto/validate_test.go
index bd4b811..490115a 100644
--- a/proto/validate_test.go
+++ b/proto/validate_test.go
@@ -23,16 +23,18 @@
 		for _, m := range test.decodeTo {
 			t.Run(fmt.Sprintf("%s (%T)", test.desc, m), func(t *testing.T) {
 				mt := m.ProtoReflect().Type()
-				want := impl.ValidationValidInitialized
+				want := impl.ValidationValid
 				if test.validationStatus != 0 {
 					want = test.validationStatus
-				} else if test.partial {
-					want = impl.ValidationValidMaybeUninitalized
 				}
 				var opts piface.UnmarshalOptions
 				opts.Resolver = protoregistry.GlobalTypes
-				if got, want := impl.Validate(test.wire, mt, opts), want; got != want {
-					t.Errorf("Validate(%x) = %v, want %v", test.wire, got, want)
+				out, status := impl.Validate(test.wire, mt, opts)
+				if status != want {
+					t.Errorf("Validate(%x) = %v, want %v", test.wire, status, want)
+				}
+				if got, want := out.Initialized, !test.partial; got != want && !test.nocheckValidInit && status == impl.ValidationValid {
+					t.Errorf("Validate(%x): initialized = %v, want %v", test.wire, got, want)
 				}
 			})
 		}
@@ -46,7 +48,9 @@
 				mt := m.ProtoReflect().Type()
 				var opts piface.UnmarshalOptions
 				opts.Resolver = protoregistry.GlobalTypes
-				if got, want := impl.Validate(test.wire, mt, opts), impl.ValidationInvalid; got != want {
+				_, got := impl.Validate(test.wire, mt, opts)
+				want := impl.ValidationInvalid
+				if got != want {
 					t.Errorf("Validate(%x) = %v, want %v", test.wire, got, want)
 				}
 			})