blob: 58bb07c1b4f8d7fd76b414545ad57dd7b4610386 [file] [log] [blame]
Joe Tsai90fe9962018-10-18 11:06:29 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Joe Tsai21ade492019-05-22 13:42:54 -04005package impl
Joe Tsai90fe9962018-10-18 11:06:29 -07006
7import (
8 "fmt"
Joe Tsai90fe9962018-10-18 11:06:29 -07009 "reflect"
Joe Tsai90fe9962018-10-18 11:06:29 -070010 "sync"
Joe Tsai90fe9962018-10-18 11:06:29 -070011
Joe Tsaid8881392019-06-06 13:01:53 -070012 "google.golang.org/protobuf/reflect/protoreflect"
Damien Neile89e6242019-05-13 23:55:40 -070013 pref "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaib2f66be2019-05-22 00:42:45 -040014 "google.golang.org/protobuf/reflect/prototype"
Joe Tsai90fe9962018-10-18 11:06:29 -070015)
16
Joe Tsai21ade492019-05-22 13:42:54 -040017// legacyWrapMessage wraps v as a protoreflect.ProtoMessage,
Joe Tsaif0c01e42018-11-06 13:05:20 -080018// where v must be a *struct kind and not implement the v2 API already.
Joe Tsai21ade492019-05-22 13:42:54 -040019func legacyWrapMessage(v reflect.Value) pref.ProtoMessage {
20 mt := legacyLoadMessageInfo(v.Type())
Joe Tsai08e00302018-11-26 22:32:06 -080021 return mt.MessageOf(v.Interface()).Interface()
Joe Tsaif0c01e42018-11-06 13:05:20 -080022}
23
Joe Tsai21ade492019-05-22 13:42:54 -040024var legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo
Joe Tsaice6edd32018-10-19 16:27:46 -070025
Joe Tsai21ade492019-05-22 13:42:54 -040026// legacyLoadMessageInfo dynamically loads a *MessageInfo for t,
Joe Tsaif0c01e42018-11-06 13:05:20 -080027// where t must be a *struct kind and not implement the v2 API already.
Joe Tsai21ade492019-05-22 13:42:54 -040028func legacyLoadMessageInfo(t reflect.Type) *MessageInfo {
Joe Tsai4fe96632019-05-22 05:12:36 -040029 // Fast-path: check if a MessageInfo is cached for this concrete type.
Joe Tsai21ade492019-05-22 13:42:54 -040030 if mt, ok := legacyMessageTypeCache.Load(t); ok {
31 return mt.(*MessageInfo)
Joe Tsaice6edd32018-10-19 16:27:46 -070032 }
33
Joe Tsai4fe96632019-05-22 05:12:36 -040034 // Slow-path: derive message descriptor and initialize MessageInfo.
Joe Tsai21ade492019-05-22 13:42:54 -040035 md := LegacyLoadMessageDesc(t)
36 mt := new(MessageInfo)
Damien Neil8012b442019-01-18 09:32:24 -080037 mt.GoType = t
Joe Tsaib2f66be2019-05-22 00:42:45 -040038 mt.PBType = &prototype.Message{
39 MessageDescriptor: md,
40 NewMessage: func() pref.Message {
41 return mt.MessageOf(reflect.New(t.Elem()).Interface())
42 },
43 }
Joe Tsai21ade492019-05-22 13:42:54 -040044 if mt, ok := legacyMessageTypeCache.LoadOrStore(t, mt); ok {
45 return mt.(*MessageInfo)
Joe Tsaib9365042019-03-19 14:14:29 -070046 }
Joe Tsaif0c01e42018-11-06 13:05:20 -080047 return mt
Joe Tsaice6edd32018-10-19 16:27:46 -070048}
49
Joe Tsaid8881392019-06-06 13:01:53 -070050var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
Joe Tsai90fe9962018-10-18 11:06:29 -070051
Joe Tsai21ade492019-05-22 13:42:54 -040052// LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type,
Joe Tsaice6edd32018-10-19 16:27:46 -070053// which must be a *struct kind and not implement the v2 API already.
Joe Tsai35ec98f2019-03-25 14:41:32 -070054//
55// This is exported for testing purposes.
Joe Tsai21ade492019-05-22 13:42:54 -040056func LegacyLoadMessageDesc(t reflect.Type) pref.MessageDescriptor {
Joe Tsai90fe9962018-10-18 11:06:29 -070057 // Fast-path: check if a MessageDescriptor is cached for this concrete type.
Joe Tsai21ade492019-05-22 13:42:54 -040058 if mi, ok := legacyMessageDescCache.Load(t); ok {
Joe Tsai90fe9962018-10-18 11:06:29 -070059 return mi.(pref.MessageDescriptor)
60 }
61
Joe Tsaid8881392019-06-06 13:01:53 -070062 // Slow-path: initialize MessageDescriptor from the raw descriptor.
Joe Tsai90fe9962018-10-18 11:06:29 -070063 mv := reflect.New(t.Elem()).Interface()
64 if _, ok := mv.(pref.ProtoMessage); ok {
65 panic(fmt.Sprintf("%v already implements proto.Message", t))
66 }
Joe Tsaid8881392019-06-06 13:01:53 -070067 mdV1, ok := mv.(messageV1)
68 if !ok {
69 panic(fmt.Sprintf("message %v is no longer supported; please regenerate", t))
70 }
71 b, idxs := mdV1.Descriptor()
Joe Tsai90fe9962018-10-18 11:06:29 -070072
Joe Tsaid8881392019-06-06 13:01:53 -070073 md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
74 for _, i := range idxs[1:] {
75 md = md.Messages().Get(i)
Joe Tsai90fe9962018-10-18 11:06:29 -070076 }
Joe Tsaid8881392019-06-06 13:01:53 -070077 if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok {
78 return md.(protoreflect.MessageDescriptor)
Joe Tsai90fe9962018-10-18 11:06:29 -070079 }
Joe Tsaid8881392019-06-06 13:01:53 -070080 return md
Joe Tsai90fe9962018-10-18 11:06:29 -070081}