You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
2.7 KiB

  1. package json
  2. import (
  3. "errors"
  4. "fmt"
  5. "reflect"
  6. tmsync "github.com/tendermint/tendermint/internal/libs/sync"
  7. )
  8. var (
  9. // typeRegistry contains globally registered types for JSON encoding/decoding.
  10. typeRegistry = newTypes()
  11. )
  12. // RegisterType registers a type for Amino-compatible interface encoding in the global type
  13. // registry. These types will be encoded with a type wrapper `{"type":"<type>","value":<value>}`
  14. // regardless of which interface they are wrapped in (if any). If the type is a pointer, it will
  15. // still be valid both for value and pointer types, but decoding into an interface will generate
  16. // the a value or pointer based on the registered type.
  17. //
  18. // Should only be called in init() functions, as it panics on error.
  19. func RegisterType(_type interface{}, name string) {
  20. if _type == nil {
  21. panic("cannot register nil type")
  22. }
  23. err := typeRegistry.register(name, reflect.ValueOf(_type).Type())
  24. if err != nil {
  25. panic(err)
  26. }
  27. }
  28. // typeInfo contains type information.
  29. type typeInfo struct {
  30. name string
  31. rt reflect.Type
  32. returnPtr bool
  33. }
  34. // types is a type registry. It is safe for concurrent use.
  35. type types struct {
  36. tmsync.RWMutex
  37. byType map[reflect.Type]*typeInfo
  38. byName map[string]*typeInfo
  39. }
  40. // newTypes creates a new type registry.
  41. func newTypes() types {
  42. return types{
  43. byType: map[reflect.Type]*typeInfo{},
  44. byName: map[string]*typeInfo{},
  45. }
  46. }
  47. // registers the given type with the given name. The name and type must not be registered already.
  48. func (t *types) register(name string, rt reflect.Type) error {
  49. if name == "" {
  50. return errors.New("name cannot be empty")
  51. }
  52. // If this is a pointer type, we recursively resolve until we get a bare type, but register that
  53. // we should return pointers.
  54. returnPtr := false
  55. for rt.Kind() == reflect.Ptr {
  56. returnPtr = true
  57. rt = rt.Elem()
  58. }
  59. tInfo := &typeInfo{
  60. name: name,
  61. rt: rt,
  62. returnPtr: returnPtr,
  63. }
  64. t.Lock()
  65. defer t.Unlock()
  66. if _, ok := t.byName[tInfo.name]; ok {
  67. return fmt.Errorf("a type with name %q is already registered", name)
  68. }
  69. if _, ok := t.byType[tInfo.rt]; ok {
  70. return fmt.Errorf("the type %v is already registered", rt)
  71. }
  72. t.byName[name] = tInfo
  73. t.byType[rt] = tInfo
  74. return nil
  75. }
  76. // lookup looks up a type from a name, or nil if not registered.
  77. func (t *types) lookup(name string) (reflect.Type, bool) {
  78. t.RLock()
  79. defer t.RUnlock()
  80. tInfo := t.byName[name]
  81. if tInfo == nil {
  82. return nil, false
  83. }
  84. return tInfo.rt, tInfo.returnPtr
  85. }
  86. // name looks up the name of a type, or empty if not registered. Unwraps pointers as necessary.
  87. func (t *types) name(rt reflect.Type) string {
  88. for rt.Kind() == reflect.Ptr {
  89. rt = rt.Elem()
  90. }
  91. t.RLock()
  92. defer t.RUnlock()
  93. tInfo := t.byType[rt]
  94. if tInfo == nil {
  95. return ""
  96. }
  97. return tInfo.name
  98. }