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.
15 func mapForm(ptr interface{}, form map[string][]string) error {
16 typ := reflect.TypeOf(ptr).Elem()
17 val := reflect.ValueOf(ptr).Elem()
18 for i := 0; i < typ.NumField(); i++ {
19 typeField := typ.Field(i)
20 structField := val.Field(i)
21 if !structField.CanSet() {
25 structFieldKind := structField.Kind()
26 inputFieldName := typeField.Tag.Get("form")
27 inputFieldNameList := strings.Split(inputFieldName, ",")
28 inputFieldName = inputFieldNameList[0]
29 var defaultValue string
30 if len(inputFieldNameList) > 1 {
31 defaultList := strings.SplitN(inputFieldNameList[1], "=", 2)
32 if defaultList[0] == "default" {
33 defaultValue = defaultList[1]
36 if inputFieldName == "" {
37 inputFieldName = typeField.Name
39 // if "form" tag is nil, we inspect if the field is a struct or struct pointer.
40 // this would not make sense for JSON parsing but it does for a form
41 // since data is flatten
42 if structFieldKind == reflect.Ptr {
43 if !structField.Elem().IsValid() {
44 structField.Set(reflect.New(structField.Type().Elem()))
46 structField = structField.Elem()
47 structFieldKind = structField.Kind()
49 if structFieldKind == reflect.Struct {
50 err := mapForm(structField.Addr().Interface(), form)
57 inputValue, exists := form[inputFieldName]
60 if defaultValue == "" {
63 inputValue = make([]string, 1)
64 inputValue[0] = defaultValue
67 numElems := len(inputValue)
68 if structFieldKind == reflect.Slice && numElems > 0 {
69 sliceOf := structField.Type().Elem().Kind()
70 slice := reflect.MakeSlice(structField.Type(), numElems, numElems)
71 for i := 0; i < numElems; i++ {
72 if err := setWithProperType(sliceOf, inputValue[i], slice.Index(i)); err != nil {
76 val.Field(i).Set(slice)
78 if _, isTime := structField.Interface().(time.Time); isTime {
79 if err := setTimeField(inputValue[0], typeField, structField); err != nil {
84 if err := setWithProperType(typeField.Type.Kind(), inputValue[0], structField); err != nil {
92 func setWithProperType(valueKind reflect.Kind, val string, structField reflect.Value) error {
95 return setIntField(val, 0, structField)
97 return setIntField(val, 8, structField)
99 return setIntField(val, 16, structField)
101 return setIntField(val, 32, structField)
103 return setIntField(val, 64, structField)
105 return setUintField(val, 0, structField)
107 return setUintField(val, 8, structField)
109 return setUintField(val, 16, structField)
111 return setUintField(val, 32, structField)
113 return setUintField(val, 64, structField)
115 return setBoolField(val, structField)
116 case reflect.Float32:
117 return setFloatField(val, 32, structField)
118 case reflect.Float64:
119 return setFloatField(val, 64, structField)
121 structField.SetString(val)
123 if !structField.Elem().IsValid() {
124 structField.Set(reflect.New(structField.Type().Elem()))
126 structFieldElem := structField.Elem()
127 return setWithProperType(structFieldElem.Kind(), val, structFieldElem)
129 return errors.New("Unknown type")
134 func setIntField(val string, bitSize int, field reflect.Value) error {
138 intVal, err := strconv.ParseInt(val, 10, bitSize)
145 func setUintField(val string, bitSize int, field reflect.Value) error {
149 uintVal, err := strconv.ParseUint(val, 10, bitSize)
151 field.SetUint(uintVal)
156 func setBoolField(val string, field reflect.Value) error {
160 boolVal, err := strconv.ParseBool(val)
162 field.SetBool(boolVal)
167 func setFloatField(val string, bitSize int, field reflect.Value) error {
171 floatVal, err := strconv.ParseFloat(val, bitSize)
173 field.SetFloat(floatVal)
178 func setTimeField(val string, structField reflect.StructField, value reflect.Value) error {
179 timeFormat := structField.Tag.Get("time_format")
180 if timeFormat == "" {
181 return errors.New("Blank time format")
185 value.Set(reflect.ValueOf(time.Time{}))
190 if isUTC, _ := strconv.ParseBool(structField.Tag.Get("time_utc")); isUTC {
194 if locTag := structField.Tag.Get("time_location"); locTag != "" {
195 loc, err := time.LoadLocation(locTag)
202 t, err := time.ParseInLocation(timeFormat, val, l)
207 value.Set(reflect.ValueOf(t))