blob: 6839412ba259da28d2ef53ea2e82098080d64a1d [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301package hscan
2
3import (
4 "fmt"
5 "reflect"
6 "strings"
7 "sync"
8)
9
10// structMap contains the map of struct fields for target structs
11// indexed by the struct type.
12type structMap struct {
13 m sync.Map
14}
15
16func newStructMap() *structMap {
17 return new(structMap)
18}
19
20func (s *structMap) get(t reflect.Type) *structSpec {
21 if v, ok := s.m.Load(t); ok {
22 return v.(*structSpec)
23 }
24
25 spec := newStructSpec(t, "redis")
26 s.m.Store(t, spec)
27 return spec
28}
29
30//------------------------------------------------------------------------------
31
32// structSpec contains the list of all fields in a target struct.
33type structSpec struct {
34 m map[string]*structField
35}
36
37func (s *structSpec) set(tag string, sf *structField) {
38 s.m[tag] = sf
39}
40
41func newStructSpec(t reflect.Type, fieldTag string) *structSpec {
42 numField := t.NumField()
43 out := &structSpec{
44 m: make(map[string]*structField, numField),
45 }
46
47 for i := 0; i < numField; i++ {
48 f := t.Field(i)
49
50 tag := f.Tag.Get(fieldTag)
51 if tag == "" || tag == "-" {
52 continue
53 }
54
55 tag = strings.Split(tag, ",")[0]
56 if tag == "" {
57 continue
58 }
59
60 // Use the built-in decoder.
61 out.set(tag, &structField{index: i, fn: decoders[f.Type.Kind()]})
62 }
63
64 return out
65}
66
67//------------------------------------------------------------------------------
68
69// structField represents a single field in a target struct.
70type structField struct {
71 index int
72 fn decoderFunc
73}
74
75//------------------------------------------------------------------------------
76
77type StructValue struct {
78 spec *structSpec
79 value reflect.Value
80}
81
82func (s StructValue) Scan(key string, value string) error {
83 field, ok := s.spec.m[key]
84 if !ok {
85 return nil
86 }
87 if err := field.fn(s.value.Field(field.index), value); err != nil {
88 t := s.value.Type()
89 return fmt.Errorf("cannot scan redis.result %s into struct field %s.%s of type %s, error-%s",
90 value, t.Name(), t.Field(field.index).Name, t.Field(field.index).Type, err.Error())
91 }
92 return nil
93}