proto: add IsInitialized

Move all checks for required fields into a proto.IsInitialized function.

Initial testing makes me confident that we can provide a fast-path
implementation of IsInitialized which will perform more than
acceptably.  (In the degenerate-but-common case where a message
transitively contains no required fields, this check can be nearly
zero cost.)

Unifying checks into a single function provides consistent behavior
between the wire, text, and json codecs.

Performing the check after decoding eliminates the wire decoder bug
where a split message is incorrectly seen as missing required fields.

Performing the check after decoding also provides consistent and
arguably more correct behavior when the target message was partially
prepopulated.

Change-Id: I9478b7bebb263af00c0d9f66a1f26e31ff553522
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170787
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/proto/encode.go b/proto/encode.go
index adf3de4..fc3ce92 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -69,10 +69,18 @@
 // MarshalAppend appends the wire-format encoding of m to b,
 // returning the result.
 func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
-	if b, err := o.marshalMessageFast(b, m); err != errInternalNoFast {
+	b, err := o.marshalMessageFast(b, m)
+	if err == errInternalNoFast {
+		b, err = o.marshalMessage(b, m.ProtoReflect())
+	}
+	var nerr errors.NonFatal
+	if !nerr.Merge(err) {
 		return b, err
 	}
-	return o.marshalMessage(b, m.ProtoReflect())
+	if !o.AllowPartial {
+		nerr.Merge(IsInitialized(m))
+	}
+	return b, nerr.E
 }
 
 func (o MarshalOptions) marshalMessageFast(b []byte, m Message) ([]byte, error) {
@@ -129,9 +137,6 @@
 		b = append(b, raw...)
 		return true
 	})
-	if !o.AllowPartial {
-		checkRequiredFields(m, &nerr)
-	}
 	return b, nerr.E
 }