internal/impl: support message and enum fields
Dynamically generate functions for handling message and enum fields,
regardless of whether they are of the v1 or v2 forms.
If a v1 message is encountered, it is automatically wrapped such that it
implements the v2 interface.
Change-Id: I457bc5286892e8fc00a61da7062dd33058daafd5
Reviewed-on: https://go-review.googlesource.com/c/143837
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/impl/legacy_message.go b/internal/impl/legacy_message.go
index a617249..66a71c6 100644
--- a/internal/impl/legacy_message.go
+++ b/internal/impl/legacy_message.go
@@ -18,10 +18,26 @@
ptype "github.com/golang/protobuf/v2/reflect/prototype"
)
+var messageTypeCache sync.Map // map[reflect.Type]*MessageType
+
+// wrapLegacyMessage wraps v as a protoreflect.Message, where v must be
+// a *struct kind and not implement the v2 API already.
+func wrapLegacyMessage(v reflect.Value) pref.Message {
+ // Fast-path: check if a MessageType is cached for this concrete type.
+ if mt, ok := messageTypeCache.Load(v.Type()); ok {
+ return mt.(*MessageType).MessageOf(v.Interface())
+ }
+
+ // Slow-path: derive message descriptor and initialize MessageType.
+ mt := &MessageType{Desc: loadMessageDesc(v.Type())}
+ messageTypeCache.Store(v.Type(), mt)
+ return mt.MessageOf(v.Interface())
+}
+
var messageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
// loadMessageDesc returns an MessageDescriptor derived from the Go type,
-// which must be an *struct kind and not implement the v2 API already.
+// which must be a *struct kind and not implement the v2 API already.
func loadMessageDesc(t reflect.Type) pref.MessageDescriptor {
return messageDescSet{}.Load(t)
}