Clean up decoders a bit.
This commit is contained in:
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user