Compare commits
3 Commits
guimaster
...
deal-with-
Author | SHA1 | Date |
---|---|---|
Alex Flint | 1f90c779f2 | |
Alex Flint | a081287ba6 | |
Alex Flint | 3a035a19bd |
43
scalar.go
43
scalar.go
|
@ -31,6 +31,40 @@ func Parse(dest interface{}, s string) error {
|
|||
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
|
||||
}
|
||||
|
||||
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.
|
||||
func ParseValue(v reflect.Value, s string) error {
|
||||
// If we have a nil pointer then allocate a new object
|
||||
|
@ -43,14 +77,15 @@ func ParseValue(v reflect.Value, s string) error {
|
|||
}
|
||||
|
||||
// If it implements encoding.TextUnmarshaler then use that
|
||||
if scalar, ok := v.Interface().(encoding.TextUnmarshaler); ok {
|
||||
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
|
||||
// via TextUnmarshaler as well
|
||||
if v.CanAddr() {
|
||||
if scalar, ok := v.Addr().Interface().(encoding.TextUnmarshaler); ok {
|
||||
return scalar.UnmarshalText([]byte(s))
|
||||
if matched, err := parseAsTextUnmarshaler(v.Addr(), s); matched {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -87,3 +87,39 @@ func TestParse(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
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