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