Initial commit

This commit is contained in:
Nise Void 2018-12-16 15:50:35 +01:00
commit e1c984b07c
Signed by: NiseVoid
GPG Key ID: FBA14AC83EA602F3
2 changed files with 163 additions and 0 deletions

111
forms.go Normal file
View File

@ -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
}

52
forms_test.go Normal file
View File

@ -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)
}