112 lines
1.8 KiB
Go
112 lines
1.8 KiB
Go
|
package forms
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
"unicode"
|
||
|
)
|
||
|
|
||
|
type Values = map[string][]string
|
||
|
|
||
|
func Decode(form Values, v interface{}) {
|
||
|
rv := reflect.ValueOf(v)
|
||
|
if rv.Kind() != reflect.Ptr {
|
||
|
panic(`Input is not a pointer`)
|
||
|
}
|
||
|
|
||
|
decode(form, rv.Elem(), ``)
|
||
|
}
|
||
|
|
||
|
func decode(form Values, rv reflect.Value, prefix string) {
|
||
|
for i := 0; i < rv.NumField(); i++ {
|
||
|
ft, fv := rv.Type().Field(i), rv.Field(i)
|
||
|
|
||
|
if !unicode.IsUpper(rune(ft.Name[0])) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
// TODO: Add custom interface
|
||
|
|
||
|
fe := ft.Type
|
||
|
if fe.Kind() == reflect.Ptr {
|
||
|
fe = fe.Elem()
|
||
|
}
|
||
|
|
||
|
if fe.Kind() == reflect.Struct {
|
||
|
if fv.Kind() == reflect.Ptr {
|
||
|
found := false
|
||
|
for k, _ := range form {
|
||
|
if strings.HasPrefix(k, getPrefix(ft, prefix)) {
|
||
|
found = true
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if !found {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||
|
|
||
|
fv = fv.Elem()
|
||
|
}
|
||
|
|
||
|
decode(form, fv, getPrefix(ft, prefix))
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
v, ok := form[getName(ft, prefix)]
|
||
|
if !ok || len(v) == 0 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if fv.Kind() != reflect.Ptr {
|
||
|
fv = fv.Addr()
|
||
|
} else if fv.IsNil() {
|
||
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||
|
}
|
||
|
|
||
|
setValue(v, fv)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func setValue(v []string, fv reflect.Value) {
|
||
|
switch f := fv.Interface().(type) {
|
||
|
case *string:
|
||
|
*f = v[0]
|
||
|
case *int:
|
||
|
*f, _ = strconv.Atoi(v[0])
|
||
|
case *float32:
|
||
|
v, _ := strconv.ParseFloat(v[0], 32)
|
||
|
*f = float32(v)
|
||
|
case *float64:
|
||
|
*f, _ = strconv.ParseFloat(v[0], 64)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
func getPrefix(ft reflect.StructField, prefix string) string {
|
||
|
if ft.Anonymous {
|
||
|
return prefix
|
||
|
}
|
||
|
|
||
|
if prefix != `` {
|
||
|
prefix += `.`
|
||
|
}
|
||
|
|
||
|
return prefix + ft.Name
|
||
|
}
|
||
|
|
||
|
func getName(ft reflect.StructField, prefix string) string {
|
||
|
name := ft.Tag.Get(`form`)
|
||
|
if name == `` {
|
||
|
name = ft.Name
|
||
|
}
|
||
|
|
||
|
if prefix == `` {
|
||
|
return name
|
||
|
}
|
||
|
|
||
|
return prefix + `.` + name
|
||
|
}
|