github.com/urso/go-structform@v0.0.2/gotype/fold.go (about) 1 package gotype 2 3 import ( 4 "reflect" 5 6 "github.com/urso/go-structform" 7 ) 8 9 type foldFn func(c *foldContext, v interface{}) error 10 11 type reFoldFn func(c *foldContext, v reflect.Value) error 12 13 type visitor interface { 14 structform.ExtVisitor 15 } 16 17 type Iterator struct { 18 ctx foldContext 19 } 20 21 type Folder interface { 22 Fold(structform.ExtVisitor) error 23 } 24 25 type foldContext struct { 26 visitor 27 userReg map[reflect.Type]reFoldFn 28 reg *typeFoldRegistry 29 opts options 30 } 31 32 func Fold(v interface{}, vs structform.Visitor, opts ...Option) error { 33 if it, err := NewIterator(vs, opts...); err == nil { 34 return it.Fold(v) 35 } 36 return nil 37 } 38 39 func NewIterator(vs structform.Visitor, opts ...Option) (*Iterator, error) { 40 reg := newTypeFoldRegistry() 41 O, err := applyOpts(opts) 42 if err != nil { 43 return nil, err 44 } 45 46 var userReg map[reflect.Type]reFoldFn 47 if O.foldFns != nil { 48 userReg = map[reflect.Type]reFoldFn{} 49 for typ, folder := range O.foldFns { 50 reg.set(typ, folder) 51 } 52 } 53 54 it := &Iterator{ 55 ctx: foldContext{ 56 visitor: structform.EnsureExtVisitor(vs).(visitor), 57 userReg: userReg, 58 reg: reg, 59 opts: options{ 60 tag: "struct", 61 }, 62 }, 63 } 64 65 return it, nil 66 } 67 68 func (i *Iterator) Fold(v interface{}) error { 69 return foldInterfaceValue(&i.ctx, v) 70 } 71 72 func foldInterfaceValue(C *foldContext, v interface{}) error { 73 if C.userReg != nil { 74 t := reflect.TypeOf(v) 75 if f := C.userReg[t]; f != nil { 76 return f(C, reflect.ValueOf(v)) 77 } 78 } 79 80 if f := getFoldGoTypes(v); f != nil { 81 return f(C, v) 82 } 83 84 if f, ok := v.(Folder); ok { 85 return f.Fold(C.visitor) 86 } 87 88 if tmp, f := getFoldConvert(v); f != nil { 89 return f(C, tmp) 90 } 91 92 return foldAnyReflect(C, reflect.ValueOf(v)) 93 } 94 95 func getFoldConvert(v interface{}) (interface{}, foldFn) { 96 t := reflect.TypeOf(v) 97 cast := false 98 99 switch t.Kind() { 100 case reflect.Map: 101 if cast = t.Name() != ""; cast { 102 mt := reflect.MapOf(t.Key(), t.Elem()) 103 v = reflect.ValueOf(v).Convert(mt).Interface() 104 } 105 case reflect.Slice: 106 if cast = t.Name() != ""; cast { 107 mt := reflect.SliceOf(t.Elem()) 108 v = reflect.ValueOf(v).Convert(mt).Interface() 109 } 110 case reflect.Array: 111 if cast = t.Name() != ""; cast { 112 mt := reflect.ArrayOf(t.Len(), t.Elem()) 113 v = reflect.ValueOf(v).Convert(mt).Interface() 114 } 115 } 116 117 return v, getFoldGoTypes(v) 118 } 119 120 func getFoldGoTypes(v interface{}) foldFn { 121 switch v.(type) { 122 case nil: 123 return foldNil 124 125 case bool: 126 return foldBool 127 case []bool: 128 return foldArrBool 129 case map[string]bool: 130 return foldMapBool 131 132 case int8: 133 return foldInt8 134 case int16: 135 return foldInt16 136 case int32: 137 return foldInt32 138 case int64: 139 return foldInt64 140 case int: 141 return foldInt 142 143 case []int8: 144 return foldArrInt8 145 case []int16: 146 return foldArrInt16 147 case []int32: 148 return foldArrInt32 149 case []int64: 150 return foldArrInt64 151 case []int: 152 return foldArrInt 153 154 case map[string]int8: 155 return foldMapInt8 156 case map[string]int16: 157 return foldMapInt16 158 case map[string]int32: 159 return foldMapInt32 160 case map[string]int64: 161 return foldMapInt64 162 case map[string]int: 163 return foldMapInt 164 165 /* 166 case byte: 167 return visitByte 168 */ 169 case uint8: 170 return foldUint8 171 case uint16: 172 return foldUint16 173 case uint32: 174 return foldUint32 175 case uint64: 176 return foldUint64 177 case uint: 178 return foldUint 179 180 case []byte: 181 return foldBytes 182 /* 183 case []uint8: 184 return visitArrUint8 185 */ 186 case []uint16: 187 return foldArrUint16 188 case []uint32: 189 return foldArrUint32 190 case []uint64: 191 return foldArrUint64 192 case []uint: 193 return foldArrUint 194 195 case map[string]uint8: 196 return foldMapUint8 197 case map[string]uint16: 198 return foldMapUint16 199 case map[string]uint32: 200 return foldMapUint32 201 case map[string]uint64: 202 return foldMapUint64 203 case map[string]uint: 204 return foldMapUint 205 206 case float32: 207 return foldFloat32 208 case float64: 209 return foldFloat64 210 211 case []float32: 212 return foldArrFloat32 213 case []float64: 214 return foldArrFloat64 215 216 case map[string]float32: 217 return foldMapFloat32 218 case map[string]float64: 219 return foldMapFloat64 220 221 case string: 222 return foldString 223 case []string: 224 return foldArrString 225 case map[string]string: 226 return foldMapString 227 228 case []interface{}: 229 return foldArrInterface 230 case map[string]interface{}: 231 return foldMapInterface 232 } 233 234 return nil 235 }