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
27 changes: 21 additions & 6 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ func (d *decoder) parseMapData() {
}

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

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

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

}
}

Expand All @@ -140,7 +138,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 +174,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 +194,27 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in
}
}
}
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the extra scope is needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was added so that v could be shadowed and modified without changing the code later on, but I'll just assign all modifications to a new var instead.

v := v // deliberately shadow v as to not modify
t := v.Type()
if t.Kind() != reflect.Ptr && v.CanAddr() {
v = v.Addr()
}
if um, ok := v.Interface().(Unmarshaler); ok {
// if receiver is a nil pointer, set before calling function.
if t.Kind() == reflect.Ptr && v.IsNil() {
t = t.Elem()
v.Set(reflect.New(t))
um = v.Interface().(Unmarshaler)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any way to avoid doing this/duplicating the Ptr logic of creating the new element?

below this same logic exists for Ptr already https://github.com/go-playground/form/pull/63/files#diff-2a967f84f1af0d52111b8dbfbeadc44bfeb1092dacebb2bc0648a0e57284c04bR226-R230.

It would be great if it's possible to keep the flow of the program using that same logic.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have a look at this and see if anything can be done

if err = um.UnmarshalForm(arr[idx:]); err != nil {
d.setError(namespace, err)
return
}
set = true
return
}
}
switch kind {
case reflect.Interface:
if !ok || idx == len(arr) {
Expand Down Expand Up @@ -602,7 +618,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
Loading