github.com/RevenueMonster/sqlike@v1.0.6/reflext/cache.go (about) 1 package reflext 2 3 import ( 4 "reflect" 5 "runtime" 6 "sync" 7 ) 8 9 // DefaultMapper : 10 var DefaultMapper = NewMapperFunc("sqlike", nil) 11 12 // StructMapper : 13 type StructMapper interface { 14 CodecByType(t reflect.Type) Structer 15 FieldByName(v reflect.Value, name string) reflect.Value 16 FieldByIndexes(v reflect.Value, idxs []int) reflect.Value 17 FieldByIndexesReadOnly(v reflect.Value, idxs []int) reflect.Value 18 LookUpFieldByName(v reflect.Value, name string) (reflect.Value, bool) 19 TraversalsByName(t reflect.Type, names []string) (idxs [][]int) 20 TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int)) (idxs [][]int) 21 } 22 23 // MapFunc : 24 type MapFunc func(StructFielder) (skip bool) 25 26 // FormatFunc : 27 type FormatFunc func(string) string 28 29 // Mapper : 30 type Mapper struct { 31 mutex sync.Mutex 32 tag string 33 cache map[reflect.Type]*Struct 34 fmtFunc FormatFunc 35 } 36 37 var _ StructMapper = (*Mapper)(nil) 38 39 // NewMapperFunc : 40 func NewMapperFunc(tag string, fmtFunc FormatFunc) *Mapper { 41 return &Mapper{ 42 cache: make(map[reflect.Type]*Struct), 43 tag: tag, 44 fmtFunc: fmtFunc, 45 } 46 } 47 48 // CodecByType : 49 func (m *Mapper) CodecByType(t reflect.Type) Structer { 50 m.mutex.Lock() 51 defer m.mutex.Unlock() 52 mapping, ok := m.cache[t] 53 if !ok { 54 mapping = getCodec(t, m.tag, m.fmtFunc) 55 m.cache[t] = mapping 56 } 57 return mapping 58 } 59 60 // FieldByName : get reflect.Value from struct by field name 61 func (m *Mapper) FieldByName(v reflect.Value, name string) reflect.Value { 62 v = Indirect(v) 63 mustBe(v, reflect.Struct) 64 65 tm := m.CodecByType(v.Type()) 66 fi, ok := tm.LookUpFieldByName(name) 67 if !ok { 68 panic("field not exists") 69 } 70 return FieldByIndexes(v, fi.Index()) 71 } 72 73 // FieldByIndexes : get reflect.Value from struct by indexes. If the reflect.Value is nil, it will get initialized 74 func (m *Mapper) FieldByIndexes(v reflect.Value, idxs []int) reflect.Value { 75 return FieldByIndexes(v, idxs) 76 } 77 78 // FieldByIndexesReadOnly : get reflect.Value from struct by indexes without initialized 79 func (m *Mapper) FieldByIndexesReadOnly(v reflect.Value, idxs []int) reflect.Value { 80 return FieldByIndexesReadOnly(v, idxs) 81 } 82 83 // LookUpFieldByName : lookup reflect.Value from struct by field name 84 func (m *Mapper) LookUpFieldByName(v reflect.Value, name string) (reflect.Value, bool) { 85 v = Indirect(v) 86 mustBe(v, reflect.Struct) 87 88 tm := m.CodecByType(v.Type()) 89 fi, ok := tm.LookUpFieldByName(name) 90 if !ok { 91 return v, false 92 } 93 return FieldByIndexes(v, fi.Index()), true 94 } 95 96 // TraversalsByName : 97 func (m *Mapper) TraversalsByName(t reflect.Type, names []string) (idxs [][]int) { 98 idxs = make([][]int, 0, len(names)) 99 m.TraversalsByNameFunc(t, names, func(i int, idx []int) { 100 if idxs != nil { 101 idxs = append(idxs, idx) 102 } else { 103 idxs = append(idxs, nil) 104 } 105 }) 106 return idxs 107 } 108 109 // TraversalsByNameFunc : 110 func (m *Mapper) TraversalsByNameFunc(t reflect.Type, names []string, fn func(int, []int)) (idxs [][]int) { 111 t = Deref(t) 112 mustBe(t, reflect.Struct) 113 114 idxs = make([][]int, 0, len(names)) 115 cdc := m.CodecByType(t) 116 for i, name := range names { 117 sf, ok := cdc.LookUpFieldByName(name) 118 if ok { 119 fn(i, sf.Index()) 120 } else { 121 fn(i, nil) 122 } 123 } 124 return idxs 125 } 126 127 // FieldByIndexes : get reflect.Value from struct by indexes. If the reflect.Value is nil, it will get initialized 128 func FieldByIndexes(v reflect.Value, indexes []int) reflect.Value { 129 for _, i := range indexes { 130 v = Indirect(v).Field(i) 131 v = Init(v) 132 } 133 return v 134 } 135 136 // FieldByIndexesReadOnly : get reflect.Value from struct by indexes without initialized 137 func FieldByIndexesReadOnly(v reflect.Value, indexes []int) reflect.Value { 138 for _, i := range indexes { 139 if v.Kind() == reflect.Ptr && v.IsNil() { 140 v = reflect.Zero(v.Type()) 141 break 142 } 143 v = Indirect(v).Field(i) 144 } 145 return v 146 } 147 148 type kinder interface { 149 Kind() reflect.Kind 150 } 151 152 func mustBe(v kinder, k reflect.Kind) { 153 if v.Kind() != k { 154 panic(&reflect.ValueError{Method: methodName(), Kind: k}) 155 } 156 } 157 158 func methodName() string { 159 pc, _, _, _ := runtime.Caller(2) 160 f := runtime.FuncForPC(pc) 161 if f == nil { 162 return "unknown method" 163 } 164 return f.Name() 165 }