commit e1c984b07c24e63f18ea2876d3dffc025ac2a8f0 Author: NiseVoid Date: Sun Dec 16 15:50:35 2018 +0100 Initial commit diff --git a/forms.go b/forms.go new file mode 100644 index 0000000..5280e41 --- /dev/null +++ b/forms.go @@ -0,0 +1,111 @@ +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 +} diff --git a/forms_test.go b/forms_test.go new file mode 100644 index 0000000..928b2eb --- /dev/null +++ b/forms_test.go @@ -0,0 +1,52 @@ +package forms + +import ( + "fmt" + "testing" +) + +type testStruct struct { + A string + B int + C float64 + D nested + + Anon + + PA *string + PD *nested +} + +type nested struct { + A string + B int + C float64 +} + +type Anon struct { + E string +} + +func TestDecode(t *testing.T) { + data := &testStruct{} + + Decode(Values{ + `A`: {`test`}, + `B`: {`10`}, + `C`: {`1.25`}, + + `D.A`: {`test2`}, + `D.B`: {`20`}, + `D.C`: {`2.50`}, + + `E`: {`test3`}, + + `PA`: {`test4`}, + + `PD.A`: {`test5`}, + `PD.B`: {`30`}, + `PD.C`: {`3.75`}, + }, data) + + fmt.Println(`data:`, data, *data.PA, *data.PD) +}