github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/libs/json/types.go (about)

     1  package json
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  
     8  	tmsync "github.com/line/ostracon/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  }