github.com/abemedia/go-don@v0.2.2-0.20240329015135-be88e32bb73b/decoder/decode.go (about) 1 package decoder 2 3 import ( 4 "errors" 5 "reflect" 6 "sync" 7 ) 8 9 var ( 10 ErrUnsupportedType = errors.New("decoder: unsupported type") 11 ErrTagNotFound = errors.New("decoder: tag not found") 12 ) 13 14 type Getter interface { 15 Get(key string) string 16 Values(key string) []string 17 } 18 19 type Decoder struct { 20 tag string 21 cache sync.Map 22 } 23 24 func New(tag string) *Decoder { 25 return &Decoder{tag: tag} 26 } 27 28 func (d *Decoder) Decode(data Getter, v any) error { 29 val := reflect.ValueOf(v) 30 if val.Kind() != reflect.Pointer { 31 return ErrUnsupportedType 32 } 33 34 val = val.Elem() 35 if val.Kind() != reflect.Struct { 36 return ErrUnsupportedType 37 } 38 39 t := val.Type() 40 41 dec, ok := d.cache.Load(t) 42 if !ok { 43 var err error 44 dec, err = compile(t, d.tag, t.Kind() == reflect.Ptr) 45 if err != nil { 46 if err != ErrTagNotFound { //nolint:errorlint,goerr113 47 return err 48 } 49 dec = noopDecoder 50 } 51 52 d.cache.Store(t, dec) 53 } 54 55 return dec.(decoder)(val, data) //nolint:forcetypeassert 56 } 57 58 type CachedDecoder[V any] struct { 59 dec decoder 60 } 61 62 func NewCached[V any](v V, tag string) (*CachedDecoder[V], error) { 63 t := reflect.TypeOf(v) 64 if t == nil { 65 return nil, ErrUnsupportedType 66 } 67 68 t, k, ptr := typeKind(t) 69 if k != reflect.Struct { 70 return nil, ErrUnsupportedType 71 } 72 73 dec, err := compile(t, tag, ptr) 74 if err != nil { 75 return nil, err 76 } 77 78 return &CachedDecoder[V]{dec}, nil 79 } 80 81 func (d *CachedDecoder[V]) Decode(data Getter, v *V) error { 82 return d.dec(reflect.ValueOf(v).Elem(), data) 83 } 84 85 func (d *CachedDecoder[V]) DecodeValue(data Getter, v reflect.Value) error { 86 return d.dec(v, data) 87 }