github.com/wfusion/gofusion@v1.1.14/http/parser/form_mapping.go (about) 1 // Fork from github.com/gin-gonic/gin@v1.7.7/binding/form_mapping.go 2 3 // Copyright 2014 Manu Martinez-Almeida. All rights reserved. 4 // Use of this source code is governed by a MIT style 5 // license that can be found in the LICENSE file. 6 7 package parser 8 9 import ( 10 "errors" 11 "fmt" 12 "reflect" 13 "strconv" 14 "strings" 15 "time" 16 17 "github.com/wfusion/gofusion/common/utils" 18 "github.com/wfusion/gofusion/common/utils/serialize/json" 19 ) 20 21 var errUnknownType = errors.New("unknown type") 22 23 var ( 24 emptyField = reflect.StructField{} 25 mapStringInterfaceSliceType = reflect.TypeOf(([]map[string]any)(nil)) 26 ) 27 28 func MapFormByTag(ptr any, form map[string][]string, tag string) error { 29 // Check if ptr is a map 30 ptrVal := reflect.ValueOf(ptr) 31 var pointed any 32 if ptrVal.Kind() == reflect.Ptr { 33 ptrVal = ptrVal.Elem() 34 pointed = ptr 35 } 36 if ptrVal.Type() == mapStringInterfaceSliceType || 37 (ptrVal.Kind() == reflect.Map && ptrVal.Type().Key().Kind() == reflect.String) { 38 if pointed != nil { 39 ptr = pointed 40 } 41 return setFormMap(ptr, form) 42 } 43 44 return mappingByPtr(ptr, formSource(form), tag) 45 } 46 47 // setter tries to set value on a walking by fields of a struct 48 type setter interface { 49 TrySet(value reflect.Value, field reflect.StructField, key string, opt setOptions) (isSetted bool, err error) 50 } 51 52 type formSource map[string][]string 53 54 var _ setter = formSource(nil) 55 56 // TrySet tries to set a value by request's form source (like map[string][]string) 57 func (form formSource) TrySet(value reflect.Value, field reflect.StructField, 58 tagValue string, opt setOptions) (isSetted bool, err error) { 59 return setByForm(value, field, form, tagValue, opt) 60 } 61 62 func mappingByPtr(ptr any, setter setter, tag string) error { 63 _, err := mapping(reflect.ValueOf(ptr), emptyField, setter, tag) 64 return err 65 } 66 67 func mapping(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { 68 if field.Tag.Get(tag) == "-" { // just ignoring this field 69 return false, nil 70 } 71 72 var vKind = value.Kind() 73 74 if vKind == reflect.Ptr { 75 var isNew bool 76 vPtr := value 77 if value.IsNil() { 78 isNew = true 79 vPtr = reflect.New(value.Type().Elem()) 80 } 81 isSetted, err := mapping(vPtr.Elem(), field, setter, tag) 82 if err != nil { 83 return false, err 84 } 85 if isNew && isSetted { 86 value.Set(vPtr) 87 } 88 return isSetted, nil 89 } 90 91 if vKind != reflect.Struct || !field.Anonymous { 92 ok, err := tryToSetValue(value, field, setter, tag) 93 if err != nil { 94 return false, err 95 } 96 if ok { 97 return true, nil 98 } 99 } 100 101 if vKind == reflect.Struct { 102 tValue := value.Type() 103 104 var isSetted bool 105 for i := 0; i < value.NumField(); i++ { 106 sf := tValue.Field(i) 107 if sf.PkgPath != "" && !sf.Anonymous { // unexported 108 continue 109 } 110 ok, err := mapping(value.Field(i), tValue.Field(i), setter, tag) 111 if err != nil { 112 return false, err 113 } 114 isSetted = isSetted || ok 115 } 116 return isSetted, nil 117 } 118 return false, nil 119 } 120 121 type setOptions struct { 122 isDefaultExists bool 123 defaultValue string 124 } 125 126 func tryToSetValue(value reflect.Value, field reflect.StructField, setter setter, tag string) (bool, error) { 127 var tagValue string 128 var setOpt setOptions 129 130 tagValue = field.Tag.Get(tag) 131 tagValue, opts := head(tagValue, ",") 132 133 if tagValue == "" { // default value is FieldName 134 tagValue = field.Name 135 } 136 if tagValue == "" { // when field is "emptyField" variable 137 return false, nil 138 } 139 140 var opt string 141 for len(opts) > 0 { 142 opt, opts = head(opts, ",") 143 144 if k, v := head(opt, "="); k == "default" { 145 setOpt.isDefaultExists = true 146 setOpt.defaultValue = v 147 } 148 } 149 150 return setter.TrySet(value, field, tagValue, setOpt) 151 } 152 153 func setByForm(value reflect.Value, field reflect.StructField, form map[string][]string, 154 tagValue string, opt setOptions) (isSetted bool, err error) { 155 vs, ok := form[tagValue] 156 if !ok && !opt.isDefaultExists { 157 return false, nil 158 } 159 160 switch value.Kind() { 161 case reflect.Slice: 162 if !ok { 163 vs = []string{opt.defaultValue} 164 } 165 return true, setSlice(vs, value, field) 166 case reflect.Array: 167 if !ok { 168 vs = []string{opt.defaultValue} 169 } 170 if len(vs) != value.Len() { 171 return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String()) 172 } 173 return true, setArray(vs, value, field) 174 default: 175 var val string 176 if !ok { 177 val = opt.defaultValue 178 } 179 180 if len(vs) > 0 { 181 val = vs[0] 182 } 183 return true, setWithProperType(val, value, field) 184 } 185 } 186 187 func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { 188 switch value.Kind() { 189 case reflect.Int: 190 return setIntField(val, 0, value) 191 case reflect.Int8: 192 return setIntField(val, 8, value) 193 case reflect.Int16: 194 return setIntField(val, 16, value) 195 case reflect.Int32: 196 return setIntField(val, 32, value) 197 case reflect.Int64: 198 switch value.Interface().(type) { 199 case time.Duration: 200 return setTimeDuration(val, value, field) 201 } 202 return setIntField(val, 64, value) 203 case reflect.Uint: 204 return setUintField(val, 0, value) 205 case reflect.Uint8: 206 return setUintField(val, 8, value) 207 case reflect.Uint16: 208 return setUintField(val, 16, value) 209 case reflect.Uint32: 210 return setUintField(val, 32, value) 211 case reflect.Uint64: 212 return setUintField(val, 64, value) 213 case reflect.Bool: 214 return setBoolField(val, value) 215 case reflect.Float32: 216 return setFloatField(val, 32, value) 217 case reflect.Float64: 218 return setFloatField(val, 64, value) 219 case reflect.String: 220 value.SetString(val) 221 case reflect.Struct: 222 switch value.Interface().(type) { 223 case time.Time: 224 return setTimeField(val, field, value) 225 } 226 return json.Unmarshal(utils.UnsafeStringToBytes(val), value.Addr().Interface()) 227 case reflect.Map: 228 return json.Unmarshal(utils.UnsafeStringToBytes(val), value.Addr().Interface()) 229 default: 230 return errUnknownType 231 } 232 return nil 233 } 234 235 func setIntField(val string, bitSize int, field reflect.Value) error { 236 if val == "" { 237 val = "0" 238 } 239 intVal, err := strconv.ParseInt(val, 10, bitSize) 240 if err == nil { 241 field.SetInt(intVal) 242 } 243 return err 244 } 245 246 func setUintField(val string, bitSize int, field reflect.Value) error { 247 if val == "" { 248 val = "0" 249 } 250 uintVal, err := strconv.ParseUint(val, 10, bitSize) 251 if err == nil { 252 field.SetUint(uintVal) 253 } 254 return err 255 } 256 257 func setBoolField(val string, field reflect.Value) error { 258 if val == "" { 259 val = "false" 260 } 261 boolVal, err := strconv.ParseBool(val) 262 if err == nil { 263 field.SetBool(boolVal) 264 } 265 return err 266 } 267 268 func setFloatField(val string, bitSize int, field reflect.Value) error { 269 if val == "" { 270 val = "0.0" 271 } 272 floatVal, err := strconv.ParseFloat(val, bitSize) 273 if err == nil { 274 field.SetFloat(floatVal) 275 } 276 return err 277 } 278 279 func setTimeField(val string, structField reflect.StructField, value reflect.Value) error { 280 timeFormat := structField.Tag.Get("time_format") 281 if timeFormat == "" { 282 timeFormat = time.RFC3339 283 } 284 285 switch tf := strings.ToLower(timeFormat); tf { 286 case "unix", "unixnano": 287 tv, err := strconv.ParseInt(val, 10, 64) 288 if err != nil { 289 return err 290 } 291 292 d := time.Duration(1) 293 if tf == "unixnano" { 294 d = time.Second 295 } 296 297 t := time.Unix(tv/int64(d), tv%int64(d)) 298 value.Set(reflect.ValueOf(t)) 299 return nil 300 301 } 302 303 if val == "" { 304 value.Set(reflect.ValueOf(time.Time{})) 305 return nil 306 } 307 308 l := time.Local 309 if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC { 310 l = time.UTC 311 } 312 313 if locTag := structField.Tag.Get("time_location"); locTag != "" { 314 loc, err := time.LoadLocation(locTag) 315 if err != nil { 316 return err 317 } 318 l = loc 319 } 320 321 t, err := time.ParseInLocation(timeFormat, val, l) 322 if err != nil { 323 return err 324 } 325 326 value.Set(reflect.ValueOf(t)) 327 return nil 328 } 329 330 func setArray(vals []string, value reflect.Value, field reflect.StructField) error { 331 for i, s := range vals { 332 err := setWithProperType(s, value.Index(i), field) 333 if err != nil { 334 return err 335 } 336 } 337 return nil 338 } 339 340 func setSlice(vals []string, value reflect.Value, field reflect.StructField) error { 341 slice := reflect.MakeSlice(value.Type(), len(vals), len(vals)) 342 err := setArray(vals, slice, field) 343 if err != nil { 344 return err 345 } 346 value.Set(slice) 347 return nil 348 } 349 350 func setTimeDuration(val string, value reflect.Value, field reflect.StructField) error { 351 d, err := time.ParseDuration(val) 352 if err != nil { 353 return err 354 } 355 value.Set(reflect.ValueOf(d)) 356 return nil 357 } 358 359 func head(str, sep string) (head string, tail string) { 360 idx := strings.Index(str, sep) 361 if idx < 0 { 362 return str, "" 363 } 364 return str[:idx], str[idx+len(sep):] 365 } 366 367 func setFormMap(ptr any, form map[string][]string) error { 368 switch ptrMap := ptr.(type) { 369 case *map[string]any: 370 *ptrMap = make(map[string]any, len(form)) 371 for k, v := range form { 372 (*ptrMap)[k] = v 373 } 374 case *[]map[string]any: 375 *ptrMap = make([]map[string]any, 0, 1) 376 tmp := make(map[string]any, len(form)) 377 for k, v := range form { 378 tmp[k] = v 379 } 380 *ptrMap = append(*ptrMap, tmp) 381 case *map[string][]string: 382 *ptrMap = make(map[string][]string, len(form)) 383 for k, v := range form { 384 (*ptrMap)[k] = v 385 } 386 case *map[string]string: 387 *ptrMap = make(map[string]string, len(form)) 388 for k, v := range form { 389 (*ptrMap)[k] = v[len(v)-1] // pick last 390 } 391 default: 392 return errors.New("cannot convert to map slices of strings") 393 } 394 395 return nil 396 }