deal with chan, map, and slice types that implement TextUnmarshaler
This commit is contained in:
parent
cfe0d0ab44
commit
3a035a19bd
47
scalar.go
47
scalar.go
|
@ -31,6 +31,42 @@ func Parse(dest interface{}, s string) error {
|
||||||
return ParseValue(reflect.ValueOf(dest), s)
|
return ParseValue(reflect.ValueOf(dest), s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseAsTextUnmarshaler(v reflect.Value, s string) (bool, error) {
|
||||||
|
t := v.Type()
|
||||||
|
if !t.Implements(textUnmarshalerType) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("parsing into %v: IsNil=%v, CanSet=%v, Kind=%v\n", t, v.IsNil(), v.CanSet(), t.Kind())
|
||||||
|
|
||||||
|
if v.IsNil() && v.CanSet() {
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Ptr:
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
case reflect.Slice:
|
||||||
|
v.Set(reflect.MakeSlice(t, 0, 0))
|
||||||
|
case reflect.Map:
|
||||||
|
v.Set(reflect.MakeMap(t))
|
||||||
|
case reflect.Chan:
|
||||||
|
v.Set(reflect.MakeChan(t, 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !v.IsNil() && t.Kind() == reflect.Ptr {
|
||||||
|
switch t.Elem().Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
v.Elem().Set(reflect.MakeSlice(t.Elem(), 0, 0))
|
||||||
|
case reflect.Map:
|
||||||
|
v.Elem().Set(reflect.MakeMap(t.Elem()))
|
||||||
|
case reflect.Chan:
|
||||||
|
v.Elem().Set(reflect.MakeChan(t.Elem(), 0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(s))
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
// ParseValue assigns a value to v by parsing s.
|
// ParseValue assigns a value to v by parsing s.
|
||||||
func ParseValue(v reflect.Value, s string) error {
|
func ParseValue(v reflect.Value, s string) error {
|
||||||
// If we have a nil pointer then allocate a new object
|
// If we have a nil pointer then allocate a new object
|
||||||
|
@ -43,14 +79,17 @@ func ParseValue(v reflect.Value, s string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it implements encoding.TextUnmarshaler then use that
|
// If it implements encoding.TextUnmarshaler then use that
|
||||||
if scalar, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
fmt.Println("attempt 1...")
|
||||||
return scalar.UnmarshalText([]byte(s))
|
if matched, err := parseAsTextUnmarshaler(v, s); matched {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's a value instead of a pointer, check that we can unmarshal it
|
// If it's a value instead of a pointer, check that we can unmarshal it
|
||||||
// via TextUnmarshaler as well
|
// via TextUnmarshaler as well
|
||||||
if v.CanAddr() {
|
if v.CanAddr() {
|
||||||
if scalar, ok := v.Addr().Interface().(encoding.TextUnmarshaler); ok {
|
fmt.Println("attempt 2...")
|
||||||
return scalar.UnmarshalText([]byte(s))
|
if matched, err := parseAsTextUnmarshaler(v, s); matched {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,3 +87,39 @@ func TestParse(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, 123, v)
|
assert.Equal(t, 123, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type sliceUnmarshaler []int
|
||||||
|
|
||||||
|
func (sliceUnmarshaler) UnmarshalText(b []byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapUnmarshaler map[string]string
|
||||||
|
|
||||||
|
func (m mapUnmarshaler) UnmarshalText(b []byte) error {
|
||||||
|
m["a"] = string(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type chanUnmarshaler chan string
|
||||||
|
|
||||||
|
func (ch chanUnmarshaler) UnmarshalText(b []byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseReferenceTypes(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
var s sliceUnmarshaler
|
||||||
|
err = Parse(&s, "test1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var m mapUnmarshaler
|
||||||
|
err = Parse(&m, "test2")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "test2", m["a"])
|
||||||
|
|
||||||
|
var c chanUnmarshaler
|
||||||
|
err = Parse(&c, "test3")
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue