github.com/hamba/avro@v1.8.0/resolver.go (about)

     1  package avro
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"time"
     7  
     8  	"github.com/modern-go/concurrent"
     9  	"github.com/modern-go/reflect2"
    10  )
    11  
    12  // TypeResolver resolves types by name.
    13  type TypeResolver struct {
    14  	names *concurrent.Map // map[string]reflect2.Type
    15  	types *concurrent.Map // map[int][]string
    16  }
    17  
    18  // NewTypeResolver creates a new type resolver with all primitive types
    19  // registered.
    20  func NewTypeResolver() *TypeResolver {
    21  	r := &TypeResolver{
    22  		names: concurrent.NewMap(),
    23  		types: concurrent.NewMap(),
    24  	}
    25  
    26  	// Register basic types
    27  	r.Register(string(Null), &null{})
    28  	r.Register(string(Int), int8(0))
    29  	r.Register(string(Int), int16(0))
    30  	r.Register(string(Int), int32(0))
    31  	r.Register(string(Int), int(0))
    32  	r.Register(string(Long), int64(0))
    33  	r.Register(string(Float), float32(0))
    34  	r.Register(string(Double), float64(0))
    35  	r.Register(string(String), "")
    36  	r.Register(string(Bytes), []byte{})
    37  	r.Register(string(Boolean), true)
    38  
    39  	// Register logical types
    40  	r.Register(string(Int)+"."+string(Date), time.Time{})
    41  	r.Register(string(Int)+"."+string(TimeMillis), time.Duration(0))
    42  	r.Register(string(Long)+"."+string(TimestampMillis), time.Time{})
    43  	r.Register(string(Long)+"."+string(TimestampMicros), time.Time{})
    44  	r.Register(string(Long)+"."+string(TimeMicros), time.Duration(0))
    45  	r.Register(string(Bytes)+"."+string(Decimal), big.NewRat(1, 1))
    46  
    47  	return r
    48  }
    49  
    50  // Register registers names to their types for resolution.
    51  func (r *TypeResolver) Register(name string, obj interface{}) {
    52  	typ := reflect2.TypeOf(obj)
    53  	rtype := typ.RType()
    54  
    55  	r.names.Store(name, typ)
    56  
    57  	raw, ok := r.types.LoadOrStore(rtype, []string{name})
    58  	if !ok {
    59  		return
    60  	}
    61  	names := raw.([]string)
    62  	names = append(names, name)
    63  	r.types.Store(rtype, names)
    64  }
    65  
    66  // Name gets the name for a type, or an error.
    67  func (r *TypeResolver) Name(typ reflect2.Type) ([]string, error) {
    68  	rtype := typ.RType()
    69  
    70  	names, ok := r.types.Load(rtype)
    71  	if !ok {
    72  		return nil, fmt.Errorf("avro: unable to resolve type %s", typ.String())
    73  	}
    74  
    75  	return names.([]string), nil
    76  }
    77  
    78  // Type gets the type for a name, or an error.
    79  func (r *TypeResolver) Type(name string) (reflect2.Type, error) {
    80  	typ, ok := r.names.Load(name)
    81  	if !ok {
    82  		return nil, fmt.Errorf("avro: unable to resolve type with name %s", name)
    83  	}
    84  
    85  	return typ.(reflect2.Type), nil
    86  }
    87  
    88  // Register registers names to their types for resolution. All primitive types are pre-registered.
    89  func Register(name string, obj interface{}) {
    90  	DefaultConfig.Register(name, obj)
    91  }