gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

form_mapping.go (9202B)


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