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), "-"))
}
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")
placeholder := ft.Tag.Get("placeholder")
if placeholder == "" {
+68 -69
View File
@@ -85,26 +85,25 @@ var (
)
// DecoderForField finds a decoder for a struct field.
//
func DecoderForField(field reflect.StructField) Decoder {
func DecoderForField(field reflect.StructField) (Decoder, error) {
name, ok := field.Tag.Lookup("type")
if ok {
if decoder, ok := namedDecoders[name]; ok {
return decoder
return decoder, nil
}
}
return DecoderForType(field.Type)
}
func DecoderForType(typ reflect.Type) Decoder {
func DecoderForType(typ reflect.Type) (Decoder, error) {
var decoder Decoder
var ok bool
if decoder, ok = typeDecoders[typ]; ok {
return decoder
return decoder, nil
} 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.
@@ -126,49 +125,19 @@ func RegisterDecoder(decoders ...Decoder) {
}
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{
reflect.Int: intDecoder,
reflect.Int8: intDecoder,
reflect.Int16: intDecoder,
reflect.Int32: intDecoder,
reflect.Int64: intDecoder,
reflect.Uint: uintDecoder,
reflect.Uint8: uintDecoder,
reflect.Uint16: uintDecoder,
reflect.Uint32: uintDecoder,
reflect.Uint64: uintDecoder,
reflect.Float32: NewKindDecoder(reflect.Float32, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
n, err := strconv.ParseFloat(scan.PopValue("float"), 32)
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.Int: NewKindDecoder(reflect.Int, intDecoder),
reflect.Int8: NewKindDecoder(reflect.Int8, intDecoder),
reflect.Int16: NewKindDecoder(reflect.Int16, intDecoder),
reflect.Int32: NewKindDecoder(reflect.Int32, intDecoder),
reflect.Int64: NewKindDecoder(reflect.Int64, intDecoder),
reflect.Uint: NewKindDecoder(reflect.Uint, uintDecoder),
reflect.Uint8: NewKindDecoder(reflect.Uint8, uintDecoder),
reflect.Uint16: NewKindDecoder(reflect.Uint16, uintDecoder),
reflect.Uint32: NewKindDecoder(reflect.Uint32, uintDecoder),
reflect.Uint64: NewKindDecoder(reflect.Uint64, uintDecoder),
reflect.Float32: NewKindDecoder(reflect.Float32, floatDecoder(32)),
reflect.Float64: NewKindDecoder(reflect.Float64, floatDecoder(64)),
reflect.String: NewKindDecoder(reflect.String, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
target.SetString(scan.PopValue("string"))
return nil
@@ -177,27 +146,57 @@ func init() {
target.SetBool(true)
return nil
}),
reflect.Slice: NewKindDecoder(reflect.Slice, func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
el := target.Type().Elem()
sep, ok := ctx.Value.Field.Tag.Lookup("sep")
if !ok {
sep = ","
}
childScanner := Scan(strings.Split(scan.PopValue("slice"), sep)...)
childDecoder := DecoderForType(el)
for childScanner.Peek().Type != EOLToken {
childValue := reflect.New(el).Elem()
err := childDecoder.Decode(ctx, childScanner, childValue)
if err != nil {
return err
}
target.Set(reflect.Append(target, childValue))
}
return nil
}),
reflect.Slice: NewKindDecoder(reflect.Slice, sliceDecoder),
}
}
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)
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()
sep, ok := ctx.Value.Field.Tag.Lookup("sep")
if !ok {
sep = ","
}
childScanner := Scan(strings.Split(scan.PopValue("list"), sep)...)
childDecoder, err := DecoderForType(el)
if err != nil {
return err
}
for childScanner.Peek().Type != EOLToken {
childValue := reflect.New(el).Elem()
err := childDecoder.Decode(ctx, childScanner, childValue)
if err != nil {
return err
}
target.Set(reflect.Append(target, childValue))
}
return nil
}