From d6a35346cc753b50a7d89cb77264fb2c64f603ef Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Sun, 20 Jun 2021 14:53:14 +0300 Subject: [PATCH] add map support Signed-off-by: Vasiliy Tolstov --- flag_test.go | 12 ++++---- util.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/flag_test.go b/flag_test.go index 6f31fb9..4966bb0 100644 --- a/flag_test.go +++ b/flag_test.go @@ -15,12 +15,14 @@ func TestLoad(t *testing.T) { os.Args = append(os.Args, "-wait", "5s") os.Args = append(os.Args, "-addr", "33,44") os.Args = append(os.Args, "-time", time.RFC822) + os.Args = append(os.Args, "-metadata", "key=20") type Config struct { - Broker string `flag:"name=broker,desc='description with, comma',default='127.0.0.1:9092'"` - Verbose bool `flag:"name=verbose,desc='verbose output',default='false'"` - Addr []string `flag:"name=addr,desc='addrs',default='127.0.0.1:9092'"` - Wait time.Duration `flag:"name=wait,desc='wait time',default='2s'"` - Time time.Time `flag:"name=time,desc='some time',default='02 Jan 06 15:04 MST'"` + Broker string `flag:"name=broker,desc='description with, comma',default='127.0.0.1:9092'"` + Verbose bool `flag:"name=verbose,desc='verbose output',default='false'"` + Addr []string `flag:"name=addr,desc='addrs',default='127.0.0.1:9092'"` + Wait time.Duration `flag:"name=wait,desc='wait time',default='2s'"` + Time time.Time `flag:"name=time,desc='some time',default='02 Jan 06 15:04 MST'"` + Metadata map[string]int `flag:"name=metadata,desc='some meta',default=''"` } ctx := context.Background() diff --git a/util.go b/util.go index 556d1c6..221b53c 100644 --- a/util.go +++ b/util.go @@ -8,6 +8,41 @@ import ( "time" ) +func convertType(v reflect.Value, t reflect.Kind) (reflect.Value, error) { + switch v.Kind() { + case reflect.String: + switch t { + case reflect.String: + return v, nil + case reflect.Int, reflect.Int64: + i, err := strconv.ParseInt(v.String(), 10, 64) + if err != nil { + return v, err + } + return reflect.ValueOf(i), nil + case reflect.Uint, reflect.Uint64: + i, err := strconv.ParseUint(v.String(), 10, 64) + if err != nil { + return v, err + } + return reflect.ValueOf(i), nil + case reflect.Float64: + i, err := strconv.ParseFloat(v.String(), 64) + if err != nil { + return v, err + } + return reflect.ValueOf(i), nil + case reflect.Bool: + i, err := strconv.ParseBool(v.String()) + if err != nil { + return v, err + } + return reflect.ValueOf(i), nil + } + } + return v, ErrInvalidValue +} + func (c *flagConfig) flagSlice(v reflect.Value, fn, fv, fd string) error { delim := DefaultSliceDelim if c.opts.Context != nil { @@ -64,6 +99,49 @@ func (c *flagConfig) flagSlice(v reflect.Value, fn, fv, fd string) error { } func (c *flagConfig) flagMap(v reflect.Value, fn, fv, fd string) error { + delim := DefaultMapDelim + if c.opts.Context != nil { + if d, ok := c.opts.Context.Value(mapDelimKey{}).(string); ok { + delim = d + } + } + flag.Func(fn, fd, func(s string) error { + ps := strings.Split(s, delim) + if len(ps) == 0 { + return nil + } + v.Set(reflect.MakeMapWithSize(v.Type(), len(ps))) + kt := v.Type().Key().Kind() + vt := v.Type().Elem().Kind() + + for i := 0; i < len(ps); i++ { + fs := strings.Split(ps[i], "=") + switch len(fs) { + case 0: + return nil + case 1: + if len(fs[0]) == 0 { + return nil + } + return ErrInvalidValue + case 2: + break + default: + return ErrInvalidValue + } + key, err := convertType(reflect.ValueOf(fs[0]), kt) + if err != nil { + return err + } + val, err := convertType(reflect.ValueOf(fs[1]), vt) + if err != nil { + return err + } + v.SetMapIndex(key.Convert(v.Type().Key()), val.Convert(v.Type().Elem())) + } + return nil + }) + return nil }