From 580b8b42f83672a203d4314c72d9623afbfc91c7 Mon Sep 17 00:00:00 2001 From: Steven Soroka Date: Thu, 17 Mar 2022 23:41:26 -0400 Subject: [PATCH] address feedback --- binding/form_mapping.go | 28 +++++++++++++++------ binding/form_mapping_test.go | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/binding/form_mapping.go b/binding/form_mapping.go index 60b5daec8d..ac8ace0b58 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -176,11 +176,17 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][ if !ok { vs = []string{opt.defaultValue} } + if ok, err := trySetCustom(vs[0], value); ok || err != nil { + return ok, err + } return true, setSlice(vs, value, field) case reflect.Array: if !ok { vs = []string{opt.defaultValue} } + if ok, err := trySetCustom(vs[0], value); ok || err != nil { + return ok, err + } if len(vs) != value.Len() { return false, fmt.Errorf("%q is not valid value for %s", vs, value.Type().String()) } @@ -194,19 +200,27 @@ func setByForm(value reflect.Value, field reflect.StructField, form map[string][ if len(vs) > 0 { val = vs[0] } + if ok, err := trySetCustom(val, value); ok || err != nil { + return ok, err + } return true, setWithProperType(val, value, field) } } -func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { - if value.Kind() != reflect.Struct { - if u, ok := value.Addr().Interface().(encoding.TextUnmarshaler); ok { - return u.UnmarshalText(bytesconv.StringToBytes(val)) +func trySetCustom(val string, value reflect.Value) (isSet bool, err error) { + switch v := value.Addr().Interface().(type) { + case encoding.TextUnmarshaler: + if value.Kind() != reflect.Struct { + return true, v.UnmarshalText([]byte(val)) } + case BindUnmarshaler: + return true, v.UnmarshalParam(val) } - if u, ok := value.Addr().Interface().(BindUnmarshaler); ok { - return u.UnmarshalParam(val) - } + + return false, nil +} + +func setWithProperType(val string, value reflect.Value, field reflect.StructField) error { switch value.Kind() { case reflect.Int: return setIntField(val, 0, value) diff --git a/binding/form_mapping_test.go b/binding/form_mapping_test.go index cdf2691ed6..b94e6792ff 100644 --- a/binding/form_mapping_test.go +++ b/binding/form_mapping_test.go @@ -351,3 +351,50 @@ func TestMappingCustomStructType(t *testing.T) { assert.EqualValues(t, "/foo", s.FileData.Path) assert.EqualValues(t, "happiness", s.FileData.Name) } + +func TestMappingCustomPointerStructType(t *testing.T) { + var s struct { + FileData *customType `form:"data"` + } + err := mappingByPtr(&s, formSource{"data": {`file:/foo:happiness`}}, "form") + assert.NoError(t, err) + + assert.EqualValues(t, "file", s.FileData.Protocol) + assert.EqualValues(t, "/foo", s.FileData.Path) + assert.EqualValues(t, "happiness", s.FileData.Name) +} + +type MySlice []string + +func (s *MySlice) UnmarshalParam(param string) error { + *s = MySlice(strings.Split(param, ",")) + return nil +} + +func TestMappingCustomSliceType(t *testing.T) { + var s struct { + Permissions MySlice `form:"permissions"` + } + err := mappingByPtr(&s, formSource{"permissions": {"read,write,delete"}}, "form") + assert.NoError(t, err) + + assert.EqualValues(t, []string{"read", "write", "delete"}, s.Permissions) +} + +type MyArray [3]string + +func (s *MyArray) UnmarshalParam(param string) error { + parts := strings.Split(param, ",") + *s = MyArray([3]string{parts[0], parts[1], parts[2]}) + return nil +} + +func TestMappingCustomArrayType(t *testing.T) { + var s struct { + Permissions MyArray `form:"permissions"` + } + err := mappingByPtr(&s, formSource{"permissions": {"read,write,delete"}}, "form") + assert.NoError(t, err) + + assert.EqualValues(t, [3]string{"read", "write", "delete"}, s.Permissions) +}