legacy_message.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. // 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. package impl
  5. import (
  6. "fmt"
  7. "reflect"
  8. "sync"
  9. "google.golang.org/protobuf/reflect/protoreflect"
  10. pref "google.golang.org/protobuf/reflect/protoreflect"
  11. "google.golang.org/protobuf/reflect/prototype"
  12. )
  13. // legacyWrapMessage wraps v as a protoreflect.ProtoMessage,
  14. // where v must be a *struct kind and not implement the v2 API already.
  15. func legacyWrapMessage(v reflect.Value) pref.ProtoMessage {
  16. mt := legacyLoadMessageInfo(v.Type())
  17. return mt.MessageOf(v.Interface()).Interface()
  18. }
  19. var legacyMessageTypeCache sync.Map // map[reflect.Type]*MessageInfo
  20. // legacyLoadMessageInfo dynamically loads a *MessageInfo for t,
  21. // where t must be a *struct kind and not implement the v2 API already.
  22. func legacyLoadMessageInfo(t reflect.Type) *MessageInfo {
  23. // Fast-path: check if a MessageInfo is cached for this concrete type.
  24. if mt, ok := legacyMessageTypeCache.Load(t); ok {
  25. return mt.(*MessageInfo)
  26. }
  27. // Slow-path: derive message descriptor and initialize MessageInfo.
  28. md := LegacyLoadMessageDesc(t)
  29. mt := new(MessageInfo)
  30. mt.GoType = t
  31. mt.PBType = &prototype.Message{
  32. MessageDescriptor: md,
  33. NewMessage: func() pref.Message {
  34. return mt.MessageOf(reflect.New(t.Elem()).Interface())
  35. },
  36. }
  37. if mt, ok := legacyMessageTypeCache.LoadOrStore(t, mt); ok {
  38. return mt.(*MessageInfo)
  39. }
  40. return mt
  41. }
  42. var legacyMessageDescCache sync.Map // map[reflect.Type]protoreflect.MessageDescriptor
  43. // LegacyLoadMessageDesc returns an MessageDescriptor derived from the Go type,
  44. // which must be a *struct kind and not implement the v2 API already.
  45. //
  46. // This is exported for testing purposes.
  47. func LegacyLoadMessageDesc(t reflect.Type) pref.MessageDescriptor {
  48. // Fast-path: check if a MessageDescriptor is cached for this concrete type.
  49. if mi, ok := legacyMessageDescCache.Load(t); ok {
  50. return mi.(pref.MessageDescriptor)
  51. }
  52. // Slow-path: initialize MessageDescriptor from the raw descriptor.
  53. mv := reflect.New(t.Elem()).Interface()
  54. if _, ok := mv.(pref.ProtoMessage); ok {
  55. panic(fmt.Sprintf("%v already implements proto.Message", t))
  56. }
  57. mdV1, ok := mv.(messageV1)
  58. if !ok {
  59. panic(fmt.Sprintf("message %v is no longer supported; please regenerate", t))
  60. }
  61. b, idxs := mdV1.Descriptor()
  62. md := legacyLoadFileDesc(b).Messages().Get(idxs[0])
  63. for _, i := range idxs[1:] {
  64. md = md.Messages().Get(i)
  65. }
  66. if md, ok := legacyMessageDescCache.LoadOrStore(t, md); ok {
  67. return md.(protoreflect.MessageDescriptor)
  68. }
  69. return md
  70. }