internal/impl: add runtime support for *[]byte unknown representation
This CL adds runtime support for unknown fields to be represented
as *[]byte in addition to the current representation as []byte.
This CL does not change generated code to use *[]byte.
Comparison between using *[]byte and []byte:
• Every message supports unknown fields, so use of []byte
expands a message size by 24B (for 64-bit systems).
In contrast, *[]byte only expands a message by 8B.
This has significant memory implications for small messages.
• If unknown fields are encountered, *[]byte has extra overhead
allocating the 24B slice header. However, it is assumed
that messages rarely see any unknown fields at runtime,
or generally do so for a temporary period of time.
Change-Id: I81935e4ea7394166e61ff4579f76f59fa792dfc9
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/244937
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/message_reflect_test.go b/internal/impl/message_reflect_test.go
index 66c2536..96c7e1b 100644
--- a/internal/impl/message_reflect_test.go
+++ b/internal/impl/message_reflect_test.go
@@ -22,6 +22,7 @@
pdesc "google.golang.org/protobuf/reflect/protodesc"
pref "google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
+ "google.golang.org/protobuf/testing/protopack"
proto2_20180125 "google.golang.org/protobuf/internal/testprotos/legacy/proto2_20180125_92554152"
testpb "google.golang.org/protobuf/internal/testprotos/test"
@@ -1425,6 +1426,43 @@
return strings.Join(ss, ".")
}
+type UnknownFieldsA struct {
+ XXX_unrecognized []byte
+}
+
+var unknownFieldsAType = pimpl.MessageInfo{
+ GoReflectType: reflect.TypeOf(new(UnknownFieldsA)),
+ Desc: mustMakeMessageDesc("unknown.proto", pref.Proto2, "", `name: "UnknownFieldsA"`, nil),
+}
+
+func (m *UnknownFieldsA) ProtoReflect() pref.Message { return unknownFieldsAType.MessageOf(m) }
+
+type UnknownFieldsB struct {
+ XXX_unrecognized *[]byte
+}
+
+var unknownFieldsBType = pimpl.MessageInfo{
+ GoReflectType: reflect.TypeOf(new(UnknownFieldsB)),
+ Desc: mustMakeMessageDesc("unknown.proto", pref.Proto2, "", `name: "UnknownFieldsB"`, nil),
+}
+
+func (m *UnknownFieldsB) ProtoReflect() pref.Message { return unknownFieldsBType.MessageOf(m) }
+
+func TestUnknownFields(t *testing.T) {
+ for _, m := range []proto.Message{new(UnknownFieldsA), new(UnknownFieldsB)} {
+ t.Run(reflect.TypeOf(m).Elem().Name(), func(t *testing.T) {
+ want := protopack.Message{
+ protopack.Tag{1, protopack.BytesType}, protopack.String("Hello, world!"),
+ }.Marshal()
+ m.ProtoReflect().SetUnknown(want)
+ got := []byte(m.ProtoReflect().GetUnknown())
+ if diff := cmp.Diff(want, got); diff != "" {
+ t.Errorf("UnknownFields mismatch (-want +got):\n%s", diff)
+ }
+ })
+ }
+}
+
func TestReset(t *testing.T) {
mi := new(testpb.TestAllTypes)