github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/ginx/cast/cast.go (about) 1 package cast 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/bingoohuang/gg/pkg/strcase" 12 ) 13 14 // TryFind tries to find value by field name or tag value. 15 func TryFind(filedName, tagValue string, getter func(string) (interface{}, bool)) (interface{}, bool) { 16 if tagValue != "" { 17 return getter(tagValue) 18 } 19 20 return TryAnyCase(filedName, getter) 21 } 22 23 // TryAnyCase tries to find value by name in any-case. 24 func TryAnyCase(name string, getter func(string) (interface{}, bool)) (interface{}, bool) { 25 if value, ok := getter(name); ok { 26 return value, true 27 } 28 29 if value, ok := getter(strcase.ToCamelLower(name)); ok { 30 return value, true 31 } 32 33 if value, ok := getter(strcase.ToSnake(name)); ok { 34 return value, true 35 } 36 37 if value, ok := getter(strcase.ToSnakeUpper(name)); ok { 38 return value, true 39 } 40 41 if value, ok := getter(strcase.ToKebab(name)); ok { 42 return value, true 43 } 44 45 if value, ok := getter(strcase.ToKebabUpper(name)); ok { 46 return value, true 47 } 48 49 return "", false 50 } 51 52 // ToStruct populates the properties to the structure's field. 53 func ToStruct(b interface{}, tagName string, getter func(filedName, tagValue string) (interface{}, bool)) error { 54 v := reflect.ValueOf(b) 55 vt := v.Type() 56 57 if vt.Kind() != reflect.Ptr { 58 return errors.New("only argument of pointer of structure supported") 59 } 60 61 v = v.Elem() 62 if vt = v.Type(); vt.Kind() != reflect.Struct { 63 return errors.New("only argument of pointer of structure supported") 64 } 65 66 for i := 0; i < vt.NumField(); i++ { 67 structField := vt.Field(i) 68 if structField.PkgPath != "" { // bypass non-exported fields 69 continue 70 } 71 72 fieldType := structField.Type 73 fieldPtr := fieldType.Kind() == reflect.Ptr 74 75 if fieldPtr { 76 fieldType = fieldType.Elem() 77 } 78 79 field := v.Field(i) 80 81 if fieldType.Kind() == reflect.Struct { 82 if err := parseStruct(fieldType, tagName, fieldPtr, field, getter); err != nil { 83 return err 84 } 85 86 continue 87 } 88 89 v, ok := getter(structField.Name, structField.Tag.Get(tagName)) 90 if !ok { 91 continue 92 } 93 94 if vs, ok := v.(string); ok { 95 vv, err := To(vs, structField.Type) 96 if err != nil { 97 return err 98 } 99 100 field.Set(vv) 101 102 continue 103 } 104 105 if reflect.TypeOf(v) == structField.Type { 106 field.Set(reflect.ValueOf(v)) 107 continue 108 } 109 110 return fmt.Errorf("unable to convert %v to %v", v, structField.Type) 111 } 112 113 return nil 114 } 115 116 func parseStruct(fieldType reflect.Type, tag string, ptr bool, field reflect.Value, 117 getter func(name string, tagValue string) (interface{}, bool), 118 ) error { 119 fv := reflect.New(fieldType) 120 if err := ToStruct(fv.Interface(), tag, getter); err != nil { 121 return err 122 } 123 124 if ptr { 125 field.Set(fv) 126 } else { 127 field.Set(fv.Elem()) 128 } 129 130 return nil 131 } 132 133 // Caster defines the function prototype for cast string a any type. 134 type Caster func(s string, asPtr bool) (reflect.Value, error) 135 136 // nolint:gochecknoglobals 137 var ( 138 InvalidValue = reflect.Value{} 139 ) 140 141 // casters defines default for basic types. 142 // nolint:gochecknoglobals 143 var casters = map[reflect.Type]Caster{ 144 reflect.TypeOf(false): toBool, 145 reflect.TypeOf(float32(0)): toFloat32, 146 reflect.TypeOf(float64(0)): toFloat64, 147 reflect.TypeOf(0): toInt, 148 reflect.TypeOf(int8(0)): toInt8, 149 reflect.TypeOf(int16(0)): toInt16, 150 reflect.TypeOf(int32(0)): toInt32, 151 reflect.TypeOf(int64(0)): toInt64, 152 reflect.TypeOf(""): toString, 153 reflect.TypeOf(uint(0)): toUint, 154 reflect.TypeOf(uint8(0)): toUint8, 155 reflect.TypeOf(uint16(0)): toUint16, 156 reflect.TypeOf(uint32(0)): toUint32, 157 reflect.TypeOf(uint64(0)): toUint64, 158 reflect.TypeOf(time.Duration(0)): toTimeDuration, 159 } 160 161 // To cast string a any type. 162 func To(s string, t reflect.Type) (reflect.Value, error) { 163 asPtr := t.Kind() == reflect.Ptr 164 if asPtr { 165 t = t.Elem() 166 } 167 168 if caster, ok := casters[t]; ok { 169 return caster(s, asPtr) 170 } 171 172 return InvalidValue, errors.New("casting not supported") 173 } 174 175 func toTimeDuration(s string, asPtr bool) (reflect.Value, error) { 176 d, err := time.ParseDuration(s) 177 if err != nil { 178 return InvalidValue, err 179 } 180 181 if asPtr { 182 return reflect.ValueOf(&d), nil 183 } 184 185 return reflect.ValueOf(d), nil 186 } 187 188 func toBool(s string, asPtr bool) (reflect.Value, error) { 189 v, err := strconv.ParseBool(s) 190 if err != nil { 191 switch strings.ToLower(s) { 192 case "yes", "ok", "1", "on": 193 v = true 194 err = nil 195 } 196 } 197 198 if err != nil { 199 return InvalidValue, err 200 } 201 202 if asPtr { 203 return reflect.ValueOf(&v), nil 204 } 205 206 return reflect.ValueOf(v), nil 207 } 208 209 func toFloat32(s string, asPtr bool) (reflect.Value, error) { 210 v, err := strconv.ParseFloat(s, 32) 211 if err != nil { 212 return InvalidValue, err 213 } 214 215 vv := float32(v) 216 217 if asPtr { 218 return reflect.ValueOf(&vv), nil 219 } 220 221 return reflect.ValueOf(vv), nil 222 } 223 224 func toFloat64(s string, asPtr bool) (reflect.Value, error) { 225 v, err := strconv.ParseFloat(s, 64) 226 if err != nil { 227 return InvalidValue, err 228 } 229 230 vv := v 231 232 if asPtr { 233 return reflect.ValueOf(&vv), nil 234 } 235 236 return reflect.ValueOf(vv), nil 237 } 238 239 func toInt(s string, asPtr bool) (reflect.Value, error) { 240 v, err := strconv.ParseInt(s, 10, 0) 241 if err != nil { 242 return InvalidValue, err 243 } 244 245 vv := int(v) 246 247 if asPtr { 248 return reflect.ValueOf(&vv), nil 249 } 250 251 return reflect.ValueOf(vv), nil 252 } 253 254 func toInt8(s string, asPtr bool) (reflect.Value, error) { 255 v, err := strconv.ParseInt(s, 10, 8) 256 if err != nil { 257 return InvalidValue, err 258 } 259 260 vv := int8(v) 261 262 if asPtr { 263 return reflect.ValueOf(&vv), nil 264 } 265 266 return reflect.ValueOf(vv), nil 267 } 268 269 func toInt16(s string, asPtr bool) (reflect.Value, error) { 270 v, err := strconv.ParseInt(s, 10, 16) 271 if err != nil { 272 return InvalidValue, err 273 } 274 275 vv := int16(v) 276 277 if asPtr { 278 return reflect.ValueOf(&vv), nil 279 } 280 281 return reflect.ValueOf(vv), nil 282 } 283 284 func toInt32(s string, asPtr bool) (reflect.Value, error) { 285 v, err := strconv.ParseInt(s, 10, 32) 286 if err != nil { 287 return InvalidValue, err 288 } 289 290 vv := int32(v) 291 292 if asPtr { 293 return reflect.ValueOf(&vv), nil 294 } 295 296 return reflect.ValueOf(vv), nil 297 } 298 299 func toInt64(s string, asPtr bool) (reflect.Value, error) { 300 v, err := strconv.ParseInt(s, 10, 64) 301 if err != nil { 302 return InvalidValue, err 303 } 304 305 if asPtr { 306 return reflect.ValueOf(&v), nil 307 } 308 309 return reflect.ValueOf(v), nil 310 } 311 312 func toString(s string, asPtr bool) (reflect.Value, error) { 313 if asPtr { 314 return reflect.ValueOf(&s), nil 315 } 316 317 return reflect.ValueOf(s), nil 318 } 319 320 func toUint(s string, asPtr bool) (reflect.Value, error) { 321 v, err := strconv.ParseUint(s, 10, 0) 322 if err != nil { 323 return InvalidValue, err 324 } 325 326 vv := uint(v) 327 328 if asPtr { 329 return reflect.ValueOf(&vv), nil 330 } 331 332 return reflect.ValueOf(vv), nil 333 } 334 335 func toUint8(s string, asPtr bool) (reflect.Value, error) { 336 v, err := strconv.ParseUint(s, 10, 8) 337 if err != nil { 338 return InvalidValue, err 339 } 340 341 vv := uint8(v) 342 343 if asPtr { 344 return reflect.ValueOf(&vv), nil 345 } 346 347 return reflect.ValueOf(vv), nil 348 } 349 350 func toUint16(s string, asPtr bool) (reflect.Value, error) { 351 v, err := strconv.ParseUint(s, 10, 16) 352 if err != nil { 353 return InvalidValue, err 354 } 355 356 vv := uint16(v) 357 358 if asPtr { 359 return reflect.ValueOf(&vv), nil 360 } 361 362 return reflect.ValueOf(vv), nil 363 } 364 365 func toUint32(s string, asPtr bool) (reflect.Value, error) { 366 v, err := strconv.ParseUint(s, 10, 32) 367 if err != nil { 368 return InvalidValue, err 369 } 370 371 vv := uint32(v) 372 373 if asPtr { 374 return reflect.ValueOf(&vv), nil 375 } 376 377 return reflect.ValueOf(vv), nil 378 } 379 380 func toUint64(s string, asPtr bool) (reflect.Value, error) { 381 v, err := strconv.ParseUint(s, 10, 64) 382 if err != nil { 383 return InvalidValue, err 384 } 385 386 if asPtr { 387 return reflect.ValueOf(&v), nil 388 } 389 390 return reflect.ValueOf(v), nil 391 }