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/encoding/textpb/decode.go b/encoding/textpb/decode.go
index 731ee64..59c98b1 100644
--- a/encoding/textpb/decode.go
+++ b/encoding/textpb/decode.go
@@ -64,6 +64,10 @@
return err
}
+ if !o.AllowPartial {
+ nerr.Merge(proto.IsInitialized(m))
+ }
+
return nerr.E
}
@@ -102,7 +106,6 @@
fieldDescs := msgType.Fields()
reservedNames := msgType.ReservedNames()
xtTypes := knownFields.ExtensionTypes()
- var reqNums set.Ints
var seenNums set.Ints
var seenOneofs set.Ints
@@ -176,25 +179,10 @@
if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
return err
}
- if !o.AllowPartial && cardinality == pref.Required {
- reqNums.Set(num)
- }
seenNums.Set(num)
}
}
- if !o.AllowPartial {
- // Check for any missing required fields.
- allReqNums := msgType.RequiredNumbers()
- if reqNums.Len() != allReqNums.Len() {
- for i := 0; i < allReqNums.Len(); i++ {
- if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
- nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
- }
- }
- }
- }
-
return nerr.E
}