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), "-"))
|
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 == "" {
|
||||||
|
|||||||
+68
-69
@@ -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,27 +146,57 @@ 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),
|
||||||
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
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var missingDecoder DecoderFunc = func(ctx *DecoderContext, scan *Scanner, target reflect.Value) error {
|
func intDecoder(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)
|
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