internal/legacy: improve performance of extension descriptor conversions
Converting to/from v1/v2 extension descriptor types is a common operation
for v1 and v2 interoperability. Optimize these operations with a cache.
Change-Id: I5feca810f60376847c791654982acd3b6a37a5db
Reviewed-on: https://go-review.googlesource.com/c/152542
Reviewed-by: Herbie Ong <herbie@google.com>
diff --git a/internal/legacy/extension_test.go b/internal/legacy/extension_test.go
new file mode 100644
index 0000000..9f431bd
--- /dev/null
+++ b/internal/legacy/extension_test.go
@@ -0,0 +1,78 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package legacy_test
+
+import (
+ "testing"
+
+ papi "github.com/golang/protobuf/protoapi"
+ pimpl "github.com/golang/protobuf/v2/internal/impl"
+ pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+ ptype "github.com/golang/protobuf/v2/reflect/prototype"
+
+ // The legacy package must be imported prior to use of any legacy messages.
+ // TODO: Remove this when protoV1 registers these hooks for you.
+ plegacy "github.com/golang/protobuf/v2/internal/legacy"
+
+ proto2_20180125 "github.com/golang/protobuf/v2/internal/testprotos/legacy/proto2.v1.0.0-20180125-92554152"
+)
+
+type legacyTestMessage struct {
+ XXX_unrecognized []byte
+ papi.XXX_InternalExtensions
+}
+
+func (*legacyTestMessage) Reset() {}
+func (*legacyTestMessage) String() string { return "" }
+func (*legacyTestMessage) ProtoMessage() {}
+func (*legacyTestMessage) ExtensionRangeArray() []papi.ExtensionRange {
+ return []papi.ExtensionRange{{Start: 10000, End: 20000}}
+}
+
+func mustMakeExtensionType(x *ptype.StandaloneExtension, v interface{}) pref.ExtensionType {
+ xd, err := ptype.NewExtension(x)
+ if err != nil {
+ panic(xd)
+ }
+ return pimpl.Export{}.ExtensionTypeOf(xd, v)
+}
+
+var (
+ parentType = pimpl.Export{}.MessageTypeOf((*legacyTestMessage)(nil))
+ messageV1Type = pimpl.Export{}.MessageTypeOf((*proto2_20180125.Message_ChildMessage)(nil))
+
+ wantType = mustMakeExtensionType(&ptype.StandaloneExtension{
+ FullName: "fizz.buzz.optional_message_v1",
+ Number: 10007,
+ Cardinality: pref.Optional,
+ Kind: pref.MessageKind,
+ MessageType: messageV1Type,
+ ExtendedType: parentType,
+ }, (*proto2_20180125.Message_ChildMessage)(nil))
+ wantDesc = &papi.ExtensionDesc{
+ ExtendedType: (*legacyTestMessage)(nil),
+ ExtensionType: (*proto2_20180125.Message_ChildMessage)(nil),
+ Field: 10007,
+ Name: "fizz.buzz.optional_message_v1",
+ Tag: "bytes,10007,opt,name=optional_message_v1",
+ }
+)
+
+func BenchmarkConvert(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ xd := plegacy.Export{}.ExtensionDescFromType(wantType)
+ gotType := plegacy.Export{}.ExtensionTypeFromDesc(xd)
+ if gotType != wantType {
+ b.Fatalf("ExtensionType mismatch: got %p, want %p", gotType, wantType)
+ }
+
+ xt := plegacy.Export{}.ExtensionTypeFromDesc(wantDesc)
+ gotDesc := plegacy.Export{}.ExtensionDescFromType(xt)
+ if gotDesc != wantDesc {
+ b.Fatalf("ExtensionDesc mismatch: got %p, want %p", gotDesc, wantDesc)
+ }
+ }
+}