Skip to content
Open
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ It has the following features:

Common Questions

- Does it support encoding.TextUnmarshaler? No because TextUnmarshaler only accepts []byte but posted values can have multiple values, so is not suitable.
- Does it support encoding.TextUnmarshaler? No, instead we have `form.Unmarshaler` because TextUnmarshaler only accepts []byte but posted values can have multiple values, so is not suitable.
- Mixing `array/slice` with `array[idx]/slice[idx]`, in which order are they parsed? `array/slice` then `array[idx]/slice[idx]`

Supported Types ( out of the box )
Expand Down Expand Up @@ -230,6 +230,33 @@ encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {
}, time.Time{})
```

Implementing Marshaler and Unmarshaler
--------------
Marshaler
```go
type CustomStruct struct {
A string
B string
}

func (c CustomStruct) MarshalForm() ([]string, error) {
return []string{ c.A, c.B }, nil
}
```

Unmarshaler
```go
type CustomStruct struct {
A string
B string
}

func (c *CustomStruct) UnmarshalForm(ss []string) error {
c.A = ss[0]
c.B = ss[1]
}
```

Ignoring Fields
--------------
you can tell form to ignore fields using `-` in the tag
Expand Down
51 changes: 45 additions & 6 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"time"
)

var unmarhsalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()

const (
errArraySize = "Array size of '%d' is larger than the maximum currently set on the decoder of '%d'. To increase this limit please see, SetMaxArraySize(size uint)"
errMissingStartBracket = "Invalid formatting for key '%s' missing '[' bracket"
Expand Down Expand Up @@ -63,7 +65,6 @@ func (d *decoder) parseMapData() {
}

for i = 0; i < len(k); i++ {

switch k[i] {
case '[':
idx = i
Expand Down Expand Up @@ -117,7 +118,6 @@ func (d *decoder) parseMapData() {

if ke.ivalue > rd.sliceLen {
rd.sliceLen = ke.ivalue

}
}

Expand All @@ -140,7 +140,6 @@ func (d *decoder) parseMapData() {
}

func (d *decoder) traverseStruct(v reflect.Value, typ reflect.Type, namespace []byte) (set bool) {

l := len(namespace)
first := l == 0

Expand Down Expand Up @@ -177,14 +176,12 @@ func (d *decoder) traverseStruct(v reflect.Value, typ reflect.Type, namespace []
}

func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx int) (set bool) {

var err error
v, kind := ExtractType(current)

arr, ok := d.values[string(namespace)]

if d.d.customTypeFuncs != nil {

if ok {
if cf, ok := d.d.customTypeFuncs[v.Type()]; ok {
val, err := cf(arr[idx:])
Expand All @@ -199,6 +196,14 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
}
}
}

if set, err = d.unmarshal(v, idx, arr); err != nil {
d.setError(namespace, err)
return
} else if set {
return
}

switch kind {
case reflect.Interface:
if !ok || idx == len(arr) {
Expand Down Expand Up @@ -602,7 +607,6 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
}

func (d *decoder) getMapKey(key string, current reflect.Value, namespace []byte) (err error) {

v, kind := ExtractType(current)

if d.d.customTypeFuncs != nil {
Expand Down Expand Up @@ -750,3 +754,38 @@ func (d *decoder) getMapKey(key string, current reflect.Value, namespace []byte)

return
}

func (d *decoder) unmarshal(v reflect.Value, idx int, arr []string) (bool, error) {
t := v.Type()
if t.Kind() != reflect.Ptr && v.CanAddr() {
v = v.Addr()
t = v.Type()
}
if v.Type().NumMethod() == 0 || !v.CanInterface() {
return false, nil
}

if !t.Implements(unmarhsalerType) {
return false, nil
}

if t.Kind() == reflect.Ptr && v.CanAddr() {
return d.unmarshalAddr(v, idx, arr)
}

um := v.Interface().(Unmarshaler)
if err := um.UnmarshalForm(arr[idx:]); err != nil {
return false, err
}
return true, nil
}

func (d *decoder) unmarshalAddr(v reflect.Value, idx int, arr []string) (bool, error) {
nv := reflect.New(v.Type().Elem())
um := nv.Interface().(Unmarshaler)
if err := um.UnmarshalForm(arr[idx:]); err != nil {
return false, err
}
v.Set(nv)
return true, nil
}
Loading