Clean up decoders a bit.

This commit is contained in:
Alec Thomas
2018-05-17 11:21:20 +10:00
parent 8f26b13088
commit cb88963909
2 changed files with 72 additions and 70 deletions
+4 -1
View File
@@ -37,7 +37,10 @@ func buildNode(v reflect.Value) *Node {
name = strings.ToLower(strings.Join(camelCase(ft.Name), "-")) name = strings.ToLower(strings.Join(camelCase(ft.Name), "-"))
} }
help := ft.Tag.Get("help") help := ft.Tag.Get("help")
decoder := DecoderForField(ft) decoder, err := DecoderForField(ft)
if err != nil && ft.Type.Kind() != reflect.Struct {
panic(err)
}
dflt := ft.Tag.Get("default") dflt := ft.Tag.Get("default")
placeholder := ft.Tag.Get("placeholder") placeholder := ft.Tag.Get("placeholder")
if placeholder == "" { if placeholder == "" {
+57 -58
View File
@@ -85,26 +85,25 @@ var (
) )
// DecoderForField finds a decoder for a struct field. // DecoderForField finds a decoder for a struct field.
// func DecoderForField(field reflect.StructField) (Decoder, error) {
func DecoderForField(field reflect.StructField) Decoder {
name, ok := field.Tag.Lookup("type") name, ok := field.Tag.Lookup("type")
if ok { if ok {
if decoder, ok := namedDecoders[name]; ok { if decoder, ok := namedDecoders[name]; ok {
return decoder return decoder, nil
} }
} }
return DecoderForType(field.Type) return DecoderForType(field.Type)
} }
func DecoderForType(typ reflect.Type) Decoder { func DecoderForType(typ reflect.Type) (Decoder, error) {
var decoder Decoder var decoder Decoder
var ok bool var ok bool
if decoder, ok = typeDecoders[typ]; ok { if decoder, ok = typeDecoders[typ]; ok {
return decoder return decoder, nil
} else if decoder, ok = kindDecoders[typ.Kind()]; ok { } else if decoder, ok = kindDecoders[typ.Kind()]; ok {
return decoder return decoder, nil
} }
return missingDecoder return nil, fmt.Errorf("no decoder for type %s", typ)
} }
// RegisterDecoder registers decoders. // RegisterDecoder registers decoders.
@@ -126,49 +125,19 @@ func RegisterDecoder(decoders ...Decoder) {
} }
func init() { func init() {
intDecoder := NewKindDecoder(reflect.Int, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseInt(scan.PopValue("int"), 10, 64)
if err != nil {
return err
}
target.SetInt(n)
return nil
})
uintDecoder := NewKindDecoder(reflect.Uint, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseUint(scan.PopValue("uint"), 10, 64)
if err != nil {
return err
}
target.SetUint(n)
return nil
})
kindDecoders = map[reflect.Kind]KindDecoder{ kindDecoders = map[reflect.Kind]KindDecoder{
reflect.Int: intDecoder, reflect.Int: NewKindDecoder(reflect.Int, intDecoder),
reflect.Int8: intDecoder, reflect.Int8: NewKindDecoder(reflect.Int8, intDecoder),
reflect.Int16: intDecoder, reflect.Int16: NewKindDecoder(reflect.Int16, intDecoder),
reflect.Int32: intDecoder, reflect.Int32: NewKindDecoder(reflect.Int32, intDecoder),
reflect.Int64: intDecoder, reflect.Int64: NewKindDecoder(reflect.Int64, intDecoder),
reflect.Uint: uintDecoder, reflect.Uint: NewKindDecoder(reflect.Uint, uintDecoder),
reflect.Uint8: uintDecoder, reflect.Uint8: NewKindDecoder(reflect.Uint8, uintDecoder),
reflect.Uint16: uintDecoder, reflect.Uint16: NewKindDecoder(reflect.Uint16, uintDecoder),
reflect.Uint32: uintDecoder, reflect.Uint32: NewKindDecoder(reflect.Uint32, uintDecoder),
reflect.Uint64: uintDecoder, reflect.Uint64: NewKindDecoder(reflect.Uint64, uintDecoder),
reflect.Float32: NewKindDecoder(reflect.Float32, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error { reflect.Float32: NewKindDecoder(reflect.Float32, floatDecoder(32)),
n, err := strconv.ParseFloat(scan.PopValue("float"), 32) reflect.Float64: NewKindDecoder(reflect.Float64, floatDecoder(64)),
if err != nil {
return err
}
target.SetFloat(n)
return nil
}),
reflect.Float64: NewKindDecoder(reflect.Float64, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseFloat(scan.PopValue("float"), 64)
if err != nil {
return err
}
target.SetFloat(n)
return nil
}),
reflect.String: NewKindDecoder(reflect.String, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error { reflect.String: NewKindDecoder(reflect.String, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
target.SetString(scan.PopValue("string")) target.SetString(scan.PopValue("string"))
return nil return nil
@@ -177,14 +146,50 @@ func init() {
target.SetBool(true) target.SetBool(true)
return nil return nil
}), }),
reflect.Slice: NewKindDecoder(reflect.Slice, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error { reflect.Slice: NewKindDecoder(reflect.Slice, sliceDecoder),
}
}
func intDecoder(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseInt(scan.PopValue("int"), 10, 64)
if err != nil {
return err
}
target.SetInt(n)
return nil
}
func uintDecoder(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseUint(scan.PopValue("uint"), 10, 64)
if err != nil {
return err
}
target.SetUint(n)
return nil
}
func floatDecoder(bits int) DecoderFunc {
return func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseFloat(scan.PopValue("float"), bits)
if err != nil {
return err
}
target.SetFloat(n)
return nil
}
}
func sliceDecoder(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
el := target.Type().Elem() el := target.Type().Elem()
sep, ok := ctx.Value.Field.Tag.Lookup("sep") sep, ok := ctx.Value.Field.Tag.Lookup("sep")
if !ok { if !ok {
sep = "," sep = ","
} }
childScanner := Scan(strings.Split(scan.PopValue("slice"), sep)...) childScanner := Scan(strings.Split(scan.PopValue("list"), sep)...)
childDecoder := DecoderForType(el) childDecoder, err := DecoderForType(el)
if err != nil {
return err
}
for childScanner.Peek().Type != EOLToken { for childScanner.Peek().Type != EOLToken {
childValue := reflect.New(el).Elem() childValue := reflect.New(el).Elem()
err := childDecoder.Decode(ctx, childScanner, childValue) err := childDecoder.Decode(ctx, childScanner, childValue)
@@ -194,10 +199,4 @@ func init() {
target.Set(reflect.Append(target, childValue)) target.Set(reflect.Append(target, childValue))
} }
return nil return nil
}),
}
}
var missingDecoder DecoderFunc = func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
return fmt.Errorf("no decoder for %q (of type %T) for field %q", target.String(), target.Type(), ctx.Value.Field.Name)
} }