options: generic options funcs #393
| @@ -1,5 +1,5 @@ | |||||||
| # Micro | # Micro | ||||||
|  |  | ||||||
| [](https://opensource.org/licenses/Apache-2.0) | [](https://opensource.org/licenses/Apache-2.0) | ||||||
| [](https://pkg.go.dev/go.unistack.org/micro/v3?tab=overview) | [](https://pkg.go.dev/go.unistack.org/micro/v3?tab=overview) | ||||||
| [](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av3+event%3Apush) | [](https://git.unistack.org/unistack-org/micro/actions?query=workflow%3Abuild+branch%3Av3+event%3Apush) | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -11,6 +11,7 @@ require ( | |||||||
| 	github.com/matoous/go-nanoid v1.5.1 | 	github.com/matoous/go-nanoid v1.5.1 | ||||||
| 	github.com/patrickmn/go-cache v2.1.0+incompatible | 	github.com/patrickmn/go-cache v2.1.0+incompatible | ||||||
| 	github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 | 	github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 | ||||||
|  | 	github.com/spf13/cast v1.7.1 | ||||||
| 	go.uber.org/automaxprocs v1.6.0 | 	go.uber.org/automaxprocs v1.6.0 | ||||||
| 	go.unistack.org/micro-proto/v3 v3.4.1 | 	go.unistack.org/micro-proto/v3 v3.4.1 | ||||||
| 	golang.org/x/sync v0.10.0 | 	golang.org/x/sync v0.10.0 | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
									
									
									
									
								
							| @@ -20,6 +20,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 | |||||||
| github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= | ||||||
| github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | ||||||
|  | github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= | ||||||
|  | github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= | ||||||
| github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= | github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= | ||||||
| github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= | github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= | ||||||
| github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||||||
| @@ -68,6 +70,8 @@ github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5 h1:G/FZtUu7a6NTWl3KUHMV9 | |||||||
| github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= | github.com/silas/dag v0.0.0-20220518035006-a7e85ada93c5/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= | ||||||
| github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= | github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= | ||||||
| github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= | ||||||
|  | github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= | ||||||
|  | github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
| github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | ||||||
|   | |||||||
							
								
								
									
										222
									
								
								options/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								options/options.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,222 @@ | |||||||
|  | package options | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"strings" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/spf13/cast" | ||||||
|  | 	mreflect "go.unistack.org/micro/v3/util/reflect" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Options interface must be used by all options | ||||||
|  | type Validator interface { | ||||||
|  | 	// Validate returns nil, if all options are correct, | ||||||
|  | 	// otherwise returns an error explaining the mistake | ||||||
|  | 	Validate() error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Option func signature | ||||||
|  | type Option func(interface{}) error | ||||||
|  |  | ||||||
|  | // Apply assign options to struct src | ||||||
|  | func Apply(src interface{}, opts ...Option) error { | ||||||
|  | 	for _, opt := range opts { | ||||||
|  | 		if err := opt(src); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetValueByPath set src struct field to val dst via path | ||||||
|  | func SetValueByPath(src interface{}, dst interface{}, path string) error { | ||||||
|  | 	var err error | ||||||
|  |  | ||||||
|  | 	switch v := dst.(type) { | ||||||
|  | 	case []interface{}: | ||||||
|  | 		if len(v) == 1 { | ||||||
|  | 			dst = v[0] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var sv reflect.Value | ||||||
|  | 	switch t := src.(type) { | ||||||
|  | 	case reflect.Value: | ||||||
|  | 		sv = t | ||||||
|  | 	default: | ||||||
|  | 		sv = reflect.ValueOf(src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	parts := strings.Split(path, ".") | ||||||
|  |  | ||||||
|  | 	for _, p := range parts { | ||||||
|  |  | ||||||
|  | 		if sv.Kind() == reflect.Ptr { | ||||||
|  | 			sv = sv.Elem() | ||||||
|  | 		} | ||||||
|  | 		if sv.Kind() != reflect.Struct { | ||||||
|  | 			return mreflect.ErrInvalidStruct | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		typ := sv.Type() | ||||||
|  | 		for idx := 0; idx < typ.NumField(); idx++ { | ||||||
|  | 			fld := typ.Field(idx) | ||||||
|  | 			val := sv.Field(idx) | ||||||
|  |  | ||||||
|  | 			/* | ||||||
|  | 				if len(fld.PkgPath) != 0 { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 			*/ | ||||||
|  |  | ||||||
|  | 			if fld.Anonymous { | ||||||
|  | 				if len(parts) == 1 && val.Kind() == reflect.Struct { | ||||||
|  | 					if err = SetValueByPath(val, dst, p); err != nil { | ||||||
|  | 						return err | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if fld.Name != p && !strings.EqualFold(strings.ToLower(fld.Name), strings.ToLower(p)) { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			switch val.Interface().(type) { | ||||||
|  | 			case []time.Duration: | ||||||
|  | 				dst, err = cast.ToDurationSliceE(dst) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				reflect.Copy(val, reflect.ValueOf(dst)) | ||||||
|  | 				return nil | ||||||
|  | 			case time.Duration: | ||||||
|  | 				dst, err = cast.ToDurationE(dst) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				val.Set(reflect.ValueOf(dst)) | ||||||
|  | 				return nil | ||||||
|  | 			case time.Time: | ||||||
|  | 				dst, err = cast.ToTimeE(dst) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				val.Set(reflect.ValueOf(dst)) | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			switch val.Kind() { | ||||||
|  | 			case reflect.Map: | ||||||
|  | 				if val.IsZero() { | ||||||
|  | 					val.Set(reflect.MakeMap(val.Type())) | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				return setMap(val.Interface(), dst) | ||||||
|  | 			case reflect.Array, reflect.Slice: | ||||||
|  | 				switch val.Type().Elem().Kind() { | ||||||
|  | 				case reflect.Bool: | ||||||
|  | 					dst, err = cast.ToBoolSliceE(dst) | ||||||
|  | 				case reflect.String: | ||||||
|  | 					dst, err = cast.ToStringSliceE(dst) | ||||||
|  | 				case reflect.Float32: | ||||||
|  | 					dst, err = toFloat32SliceE(dst) | ||||||
|  | 				case reflect.Float64: | ||||||
|  | 					dst, err = toFloat64SliceE(dst) | ||||||
|  | 				case reflect.Int8: | ||||||
|  | 					dst, err = toInt8SliceE(dst) | ||||||
|  | 				case reflect.Int: | ||||||
|  | 					dst, err = cast.ToIntSliceE(dst) | ||||||
|  | 				case reflect.Int16: | ||||||
|  | 					dst, err = toInt16SliceE(dst) | ||||||
|  | 				case reflect.Int32: | ||||||
|  | 					dst, err = toInt32SliceE(dst) | ||||||
|  | 				case reflect.Int64: | ||||||
|  | 					dst, err = toInt64SliceE(dst) | ||||||
|  | 				case reflect.Uint8: | ||||||
|  | 					dst, err = toUint8SliceE(dst) | ||||||
|  | 				case reflect.Uint: | ||||||
|  | 					dst, err = toUintSliceE(dst) | ||||||
|  | 				case reflect.Uint16: | ||||||
|  | 					dst, err = toUint16SliceE(dst) | ||||||
|  | 				case reflect.Uint32: | ||||||
|  | 					dst, err = toUint32SliceE(dst) | ||||||
|  | 				case reflect.Uint64: | ||||||
|  | 					dst, err = toUint64SliceE(dst) | ||||||
|  | 				} | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				if val.Kind() == reflect.Slice { | ||||||
|  | 					val.Set(reflect.ValueOf(dst)) | ||||||
|  | 				} else { | ||||||
|  | 					reflect.Copy(val, reflect.ValueOf(dst)) | ||||||
|  | 				} | ||||||
|  | 				return nil | ||||||
|  | 			case reflect.Float32: | ||||||
|  | 				dst, err = toFloat32SliceE(dst) | ||||||
|  | 			case reflect.Float64: | ||||||
|  | 				dst, err = toFloat64SliceE(dst) | ||||||
|  | 			case reflect.Bool: | ||||||
|  | 				dst, err = cast.ToBoolE(dst) | ||||||
|  | 			case reflect.String: | ||||||
|  | 				dst, err = cast.ToStringE(dst) | ||||||
|  | 			case reflect.Int8: | ||||||
|  | 				dst, err = cast.ToInt8E(dst) | ||||||
|  | 			case reflect.Int: | ||||||
|  | 				dst, err = cast.ToIntE(dst) | ||||||
|  | 			case reflect.Int16: | ||||||
|  | 				dst, err = cast.ToInt16E(dst) | ||||||
|  | 			case reflect.Int32: | ||||||
|  | 				dst, err = cast.ToInt32E(dst) | ||||||
|  | 			case reflect.Int64: | ||||||
|  | 				dst, err = cast.ToInt64E(dst) | ||||||
|  | 			case reflect.Uint8: | ||||||
|  | 				dst, err = cast.ToUint8E(dst) | ||||||
|  | 			case reflect.Uint: | ||||||
|  | 				dst, err = cast.ToUintE(dst) | ||||||
|  | 			case reflect.Uint16: | ||||||
|  | 				dst, err = cast.ToUint16E(dst) | ||||||
|  | 			case reflect.Uint32: | ||||||
|  | 				dst, err = cast.ToUint32E(dst) | ||||||
|  | 			case reflect.Uint64: | ||||||
|  | 				dst, err = cast.ToUint64E(dst) | ||||||
|  | 			default: | ||||||
|  | 			} | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			val.Set(reflect.ValueOf(dst)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewOption create new option with name | ||||||
|  | func NewOption(name string) func(...interface{}) Option { | ||||||
|  | 	return func(dst ...interface{}) Option { | ||||||
|  | 		return func(src interface{}) error { | ||||||
|  | 			return SetValueByPath(src, dst, name) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	Address   = NewOption("Address") | ||||||
|  | 	Name      = NewOption("Name") | ||||||
|  | 	Broker    = NewOption("Broker") | ||||||
|  | 	Logger    = NewOption("Logger") | ||||||
|  | 	Meter     = NewOption("Meter") | ||||||
|  | 	Tracer    = NewOption("Tracer") | ||||||
|  | 	Store     = NewOption("Store") | ||||||
|  | 	Register  = NewOption("Register") | ||||||
|  | 	Router    = NewOption("Router") | ||||||
|  | 	Codec     = NewOption("Codec") | ||||||
|  | 	Codecs    = NewOption("Codecs") | ||||||
|  | 	Client    = NewOption("Client") | ||||||
|  | 	Context   = NewOption("Context") | ||||||
|  | 	TLSConfig = NewOption("TLSConfig") | ||||||
|  | 	Metadata  = NewOption("Metadata") | ||||||
|  | 	Timeout   = NewOption("Timeout") | ||||||
|  | ) | ||||||
							
								
								
									
										181
									
								
								options/options_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								options/options_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | package options_test | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"crypto/tls" | ||||||
|  | 	"sync" | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"go.unistack.org/micro/v3/options" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type codec interface { | ||||||
|  | 	Marshal(v interface{}, opts ...options.Option) ([]byte, error) | ||||||
|  | 	Unmarshal(b []byte, v interface{}, opts ...options.Option) error | ||||||
|  | 	String() string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestCodecs(t *testing.T) { | ||||||
|  | 	type s struct { | ||||||
|  | 		Codecs map[string]codec | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	wg := &sync.WaitGroup{} | ||||||
|  | 	tc := &tls.Config{InsecureSkipVerify: true} | ||||||
|  | 	opts := []options.Option{ | ||||||
|  | 		options.NewOption("Codecs")(wg), | ||||||
|  | 		options.NewOption("TLSConfig")(tc), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	src := &s{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestSpecial(t *testing.T) { | ||||||
|  | 	type s struct { | ||||||
|  | 		Wait      *sync.WaitGroup | ||||||
|  | 		TLSConfig *tls.Config | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	wg := &sync.WaitGroup{} | ||||||
|  | 	tc := &tls.Config{InsecureSkipVerify: true} | ||||||
|  | 	opts := []options.Option{ | ||||||
|  | 		options.NewOption("Wait")(wg), | ||||||
|  | 		options.NewOption("TLSConfig")(tc), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	src := &s{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Wait == nil { | ||||||
|  | 		t.Fatalf("failed to set Wait %#+v", src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.TLSConfig == nil { | ||||||
|  | 		t.Fatalf("failed to set TLSConfig %#+v", src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.TLSConfig.InsecureSkipVerify != true { | ||||||
|  | 		t.Fatalf("failed to set TLSConfig %#+v", src) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestNested(t *testing.T) { | ||||||
|  | 	type server struct { | ||||||
|  | 		Address []string | ||||||
|  | 	} | ||||||
|  | 	type ownserver struct { | ||||||
|  | 		server | ||||||
|  | 		OwnField string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opts := []options.Option{ | ||||||
|  | 		options.Address("host:port"), | ||||||
|  | 		options.NewOption("OwnField")("fieldval"), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	src := &ownserver{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Address[0] != "host:port" { | ||||||
|  | 		t.Fatalf("failed to set Address %#+v", src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.OwnField != "fieldval" { | ||||||
|  | 		t.Fatalf("failed to set OwnField %#+v", src) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestAddress(t *testing.T) { | ||||||
|  | 	type s struct { | ||||||
|  | 		Address []string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opts := []options.Option{options.Address("host:port")} | ||||||
|  |  | ||||||
|  | 	src := &s{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Address[0] != "host:port" { | ||||||
|  | 		t.Fatalf("failed to set Address %#+v", src) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestNewOption(t *testing.T) { | ||||||
|  | 	type s struct { | ||||||
|  | 		Address []string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opts := []options.Option{options.NewOption("Address")("host1:port1", "host2:port2")} | ||||||
|  |  | ||||||
|  | 	src := &s{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Address[0] != "host1:port1" { | ||||||
|  | 		t.Fatalf("failed to set Address %#+v", src) | ||||||
|  | 	} | ||||||
|  | 	if src.Address[1] != "host2:port2" { | ||||||
|  | 		t.Fatalf("failed to set Address %#+v", src) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestArray(t *testing.T) { | ||||||
|  | 	type s struct { | ||||||
|  | 		Address [1]string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opts := []options.Option{options.NewOption("Address")("host:port", "host1:port1")} | ||||||
|  |  | ||||||
|  | 	src := &s{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Address[0] != "host:port" { | ||||||
|  | 		t.Fatalf("failed to set Address %#+v", src) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestMap(t *testing.T) { | ||||||
|  | 	type s struct { | ||||||
|  | 		Metadata map[string]string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opts := []options.Option{ | ||||||
|  | 		options.NewOption("Metadata")("key1", "val1"), | ||||||
|  | 		options.NewOption("Metadata")(map[string]string{"key2": "val2"}), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	src := &s{} | ||||||
|  |  | ||||||
|  | 	if err := options.Apply(src, opts...); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(src.Metadata) != 2 { | ||||||
|  | 		t.Fatalf("failed to set Metadata %#+v", src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Metadata["key1"] != "val1" { | ||||||
|  | 		t.Fatalf("failed to set Metadata %#+v", src) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if src.Metadata["key2"] != "val2" { | ||||||
|  | 		t.Fatalf("failed to set Metadata %#+v", src) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										577
									
								
								options/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										577
									
								
								options/util.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,577 @@ | |||||||
|  | package options | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  |  | ||||||
|  | 	"github.com/spf13/cast" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func toInt8SliceE(i interface{}) ([]int8, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []int8{}, fmt.Errorf("unable to cast %#v of type %T to []int8", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []int8: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]int8, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToInt8E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []int8{}, fmt.Errorf("unable to cast %#v of type %T to []int8", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []int8{}, fmt.Errorf("unable to cast %#v of type %T to []int8", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toInt16SliceE(i interface{}) ([]int16, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []int16{}, fmt.Errorf("unable to cast %#v of type %T to []int16", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []int16: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]int16, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToInt16E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []int16{}, fmt.Errorf("unable to cast %#v of type %T to []int16", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []int16{}, fmt.Errorf("unable to cast %#v of type %T to []int16", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toInt32SliceE(i interface{}) ([]int32, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []int32{}, fmt.Errorf("unable to cast %#v of type %T to []int32", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []int32: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]int32, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToInt32E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []int32{}, fmt.Errorf("unable to cast %#v of type %T to []int32", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []int32{}, fmt.Errorf("unable to cast %#v of type %T to []int32", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toInt64SliceE(i interface{}) ([]int64, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []int64{}, fmt.Errorf("unable to cast %#v of type %T to []int64", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []int64: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]int64, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToInt64E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []int64{}, fmt.Errorf("unable to cast %#v of type %T to []int64", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []int64{}, fmt.Errorf("unable to cast %#v of type %T to []int64", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toUintSliceE(i interface{}) ([]uint, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []uint{}, fmt.Errorf("unable to cast %#v of type %T to []uint", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []uint: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]uint, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToUintE(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []uint{}, fmt.Errorf("unable to cast %#v of type %T to []uint", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []uint{}, fmt.Errorf("unable to cast %#v of type %T to []uint", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toUint8SliceE(i interface{}) ([]uint8, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []uint8{}, fmt.Errorf("unable to cast %#v of type %T to []uint8", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []uint8: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]uint8, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToUint8E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []uint8{}, fmt.Errorf("unable to cast %#v of type %T to []uint8", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []uint8{}, fmt.Errorf("unable to cast %#v of type %T to []uint8", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toUint16SliceE(i interface{}) ([]uint16, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []uint16{}, fmt.Errorf("unable to cast %#v of type %T to []uint16", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []uint16: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]uint16, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToUint16E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []uint16{}, fmt.Errorf("unable to cast %#v of type %T to []uint16", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []uint16{}, fmt.Errorf("unable to cast %#v of type %T to []uint16", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toUint32SliceE(i interface{}) ([]uint32, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []uint32{}, fmt.Errorf("unable to cast %#v of type %T to []uint32", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []uint32: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]uint32, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToUint32E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []uint32{}, fmt.Errorf("unable to cast %#v of type %T to []uint32", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []uint32{}, fmt.Errorf("unable to cast %#v of type %T to []uint32", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toUint64SliceE(i interface{}) ([]uint64, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []uint64{}, fmt.Errorf("unable to cast %#v of type %T to []uint64", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []uint64: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]uint64, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToUint64E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []uint64{}, fmt.Errorf("unable to cast %#v of type %T to []uint64", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []uint64{}, fmt.Errorf("unable to cast %#v of type %T to []uint64", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toFloat32SliceE(i interface{}) ([]float32, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []float32{}, fmt.Errorf("unable to cast %#v of type %T to []float32", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []float32: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]float32, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToFloat32E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []float32{}, fmt.Errorf("unable to cast %#v of type %T to []float32", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []float32{}, fmt.Errorf("unable to cast %#v of type %T to []float32", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func toFloat64SliceE(i interface{}) ([]float64, error) { | ||||||
|  | 	if i == nil { | ||||||
|  | 		return []float64{}, fmt.Errorf("unable to cast %#v of type %T to []float64", i, i) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	switch v := i.(type) { | ||||||
|  | 	case []float64: | ||||||
|  | 		return v, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	kind := reflect.TypeOf(i).Kind() | ||||||
|  | 	switch kind { | ||||||
|  | 	case reflect.Slice, reflect.Array: | ||||||
|  | 		s := reflect.ValueOf(i) | ||||||
|  | 		a := make([]float64, s.Len()) | ||||||
|  | 		for j := 0; j < s.Len(); j++ { | ||||||
|  | 			val, err := cast.ToFloat64E(s.Index(j).Interface()) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return []float64{}, fmt.Errorf("unable to cast %#v of type %T to []float64", i, i) | ||||||
|  | 			} | ||||||
|  | 			a[j] = val | ||||||
|  | 		} | ||||||
|  | 		return a, nil | ||||||
|  | 	default: | ||||||
|  | 		return []float64{}, fmt.Errorf("unable to cast %#v of type %T to []float32", i, i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func setMap(src interface{}, dst interface{}) error { | ||||||
|  | 	var err error | ||||||
|  |  | ||||||
|  | 	if src == nil { | ||||||
|  | 		return fmt.Errorf("unable to cast %#v of type %T", src, src) | ||||||
|  | 	} | ||||||
|  | 	if dst == nil { | ||||||
|  | 		return fmt.Errorf("unable to cast %#v of type %T", dst, dst) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	val := reflect.ValueOf(src) | ||||||
|  |  | ||||||
|  | 	keyKind := val.Type().Key().Kind() | ||||||
|  | 	valKind := val.Type().Elem().Kind() | ||||||
|  |  | ||||||
|  | 	switch v := dst.(type) { | ||||||
|  | 	case []interface{}: | ||||||
|  | 		if len(v) == 1 { | ||||||
|  | 			dstVal := reflect.ValueOf(v[0]) | ||||||
|  | 			if dstVal.Kind() != reflect.Map { | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 			mapIter := dstVal.MapRange() | ||||||
|  | 			for mapIter.Next() { | ||||||
|  | 				var ( | ||||||
|  | 					keyVal interface{} | ||||||
|  | 					valVal interface{} | ||||||
|  | 				) | ||||||
|  | 				switch keyKind { | ||||||
|  | 				case reflect.Bool: | ||||||
|  | 					keyVal, err = cast.ToBoolE(mapIter.Key()) | ||||||
|  | 				case reflect.String: | ||||||
|  | 					keyVal, err = cast.ToStringE(mapIter.Key()) | ||||||
|  | 				case reflect.Float32: | ||||||
|  | 					keyVal, err = cast.ToFloat32E(mapIter.Key()) | ||||||
|  | 				case reflect.Float64: | ||||||
|  | 					keyVal, err = cast.ToFloat64E(mapIter.Key()) | ||||||
|  | 				case reflect.Int8: | ||||||
|  | 					keyVal, err = cast.ToInt8E(mapIter.Key()) | ||||||
|  | 				case reflect.Int: | ||||||
|  | 					keyVal, err = cast.ToIntE(mapIter.Key()) | ||||||
|  | 				case reflect.Int16: | ||||||
|  | 					keyVal, err = cast.ToInt16E(mapIter.Key()) | ||||||
|  | 				case reflect.Int32: | ||||||
|  | 					keyVal, err = cast.ToInt32E(mapIter.Key()) | ||||||
|  | 				case reflect.Int64: | ||||||
|  | 					keyVal, err = cast.ToInt64E(mapIter.Key()) | ||||||
|  | 				case reflect.Uint8: | ||||||
|  | 					keyVal, err = cast.ToUint8E(mapIter.Key()) | ||||||
|  | 				case reflect.Uint: | ||||||
|  | 					keyVal, err = cast.ToUintE(mapIter.Key()) | ||||||
|  | 				case reflect.Uint16: | ||||||
|  | 					keyVal, err = cast.ToUint16E(mapIter.Key()) | ||||||
|  | 				case reflect.Uint32: | ||||||
|  | 					keyVal, err = cast.ToUint32E(mapIter.Key()) | ||||||
|  | 				case reflect.Uint64: | ||||||
|  | 					keyVal, err = cast.ToUint64E(mapIter.Key()) | ||||||
|  | 				} | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 				switch valKind { | ||||||
|  | 				case reflect.Bool: | ||||||
|  | 					valVal, err = cast.ToBoolE(mapIter.Value()) | ||||||
|  | 				case reflect.String: | ||||||
|  | 					valVal, err = cast.ToStringE(mapIter.Value()) | ||||||
|  | 				case reflect.Float32: | ||||||
|  | 					valVal, err = cast.ToFloat32E(mapIter.Value()) | ||||||
|  | 				case reflect.Float64: | ||||||
|  | 					valVal, err = cast.ToFloat64E(mapIter.Value()) | ||||||
|  | 				case reflect.Int8: | ||||||
|  | 					valVal, err = cast.ToInt8E(mapIter.Value()) | ||||||
|  | 				case reflect.Int: | ||||||
|  | 					valVal, err = cast.ToIntE(mapIter.Value()) | ||||||
|  | 				case reflect.Int16: | ||||||
|  | 					valVal, err = cast.ToInt16E(mapIter.Value()) | ||||||
|  | 				case reflect.Int32: | ||||||
|  | 					valVal, err = cast.ToInt32E(mapIter.Value()) | ||||||
|  | 				case reflect.Int64: | ||||||
|  | 					valVal, err = cast.ToInt64E(mapIter.Value()) | ||||||
|  | 				case reflect.Uint8: | ||||||
|  | 					valVal, err = cast.ToUint8E(mapIter.Value()) | ||||||
|  | 				case reflect.Uint: | ||||||
|  | 					valVal, err = cast.ToUintE(mapIter.Value()) | ||||||
|  | 				case reflect.Uint16: | ||||||
|  | 					valVal, err = cast.ToUint16E(mapIter.Value()) | ||||||
|  | 				case reflect.Uint32: | ||||||
|  | 					valVal, err = cast.ToUint32E(mapIter.Value()) | ||||||
|  | 				case reflect.Uint64: | ||||||
|  | 					valVal, err = cast.ToUint64E(mapIter.Value()) | ||||||
|  | 				} | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				val.SetMapIndex(reflect.ValueOf(keyVal), reflect.ValueOf(valVal)) | ||||||
|  | 			} | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		if l := len(v) % 2; l == 1 { | ||||||
|  | 			v = v[:len(v)-1] | ||||||
|  | 		} | ||||||
|  | 		var ( | ||||||
|  | 			keyVal interface{} | ||||||
|  | 			valVal interface{} | ||||||
|  | 		) | ||||||
|  | 		for i := 0; i < len(v); i += 2 { | ||||||
|  | 			switch keyKind { | ||||||
|  | 			case reflect.Bool: | ||||||
|  | 				keyVal, err = cast.ToBoolE(v[i]) | ||||||
|  | 			case reflect.String: | ||||||
|  | 				keyVal, err = cast.ToStringE(v[i]) | ||||||
|  | 			case reflect.Float32: | ||||||
|  | 				keyVal, err = cast.ToFloat32E(v[i]) | ||||||
|  | 			case reflect.Float64: | ||||||
|  | 				keyVal, err = cast.ToFloat64E(v[i]) | ||||||
|  | 			case reflect.Int8: | ||||||
|  | 				keyVal, err = cast.ToInt8E(v[i]) | ||||||
|  | 			case reflect.Int: | ||||||
|  | 				keyVal, err = cast.ToIntE(v[i]) | ||||||
|  | 			case reflect.Int16: | ||||||
|  | 				keyVal, err = cast.ToInt16E(v[i]) | ||||||
|  | 			case reflect.Int32: | ||||||
|  | 				keyVal, err = cast.ToInt32E(v[i]) | ||||||
|  | 			case reflect.Int64: | ||||||
|  | 				keyVal, err = cast.ToInt64E(v[i]) | ||||||
|  | 			case reflect.Uint8: | ||||||
|  | 				keyVal, err = cast.ToUint8E(v[i]) | ||||||
|  | 			case reflect.Uint: | ||||||
|  | 				keyVal, err = cast.ToUintE(v[i]) | ||||||
|  | 			case reflect.Uint16: | ||||||
|  | 				keyVal, err = cast.ToUint16E(v[i]) | ||||||
|  | 			case reflect.Uint32: | ||||||
|  | 				keyVal, err = cast.ToUint32E(v[i]) | ||||||
|  | 			case reflect.Uint64: | ||||||
|  | 				keyVal, err = cast.ToUint64E(v[i]) | ||||||
|  | 			} | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			switch valKind { | ||||||
|  | 			case reflect.Bool: | ||||||
|  | 				valVal, err = cast.ToBoolE(v[i+1]) | ||||||
|  | 			case reflect.String: | ||||||
|  | 				valVal, err = cast.ToStringE(v[i+1]) | ||||||
|  | 			case reflect.Float32: | ||||||
|  | 				valVal, err = cast.ToFloat32E(v[i+1]) | ||||||
|  | 			case reflect.Float64: | ||||||
|  | 				valVal, err = cast.ToFloat64E(v[i+1]) | ||||||
|  | 			case reflect.Int8: | ||||||
|  | 				valVal, err = cast.ToInt8E(v[i+1]) | ||||||
|  | 			case reflect.Int: | ||||||
|  | 				valVal, err = cast.ToIntE(v[i+1]) | ||||||
|  | 			case reflect.Int16: | ||||||
|  | 				valVal, err = cast.ToInt16E(v[i+1]) | ||||||
|  | 			case reflect.Int32: | ||||||
|  | 				valVal, err = cast.ToInt32E(v[i+1]) | ||||||
|  | 			case reflect.Int64: | ||||||
|  | 				valVal, err = cast.ToInt64E(v[i+1]) | ||||||
|  | 			case reflect.Uint8: | ||||||
|  | 				valVal, err = cast.ToUint8E(v[i+1]) | ||||||
|  | 			case reflect.Uint: | ||||||
|  | 				valVal, err = cast.ToUintE(v[i+1]) | ||||||
|  | 			case reflect.Uint16: | ||||||
|  | 				valVal, err = cast.ToUint16E(v[i+1]) | ||||||
|  | 			case reflect.Uint32: | ||||||
|  | 				valVal, err = cast.ToUint32E(v[i+1]) | ||||||
|  | 			case reflect.Uint64: | ||||||
|  | 				valVal, err = cast.ToUint64E(v[i+1]) | ||||||
|  | 			} | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			val.SetMapIndex(reflect.ValueOf(keyVal), reflect.ValueOf(valVal)) | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		dstVal := reflect.ValueOf(dst) | ||||||
|  | 		if dstVal.Kind() != reflect.Map { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		mapIter := dstVal.MapRange() | ||||||
|  | 		for mapIter.Next() { | ||||||
|  | 			var ( | ||||||
|  | 				keyVal interface{} | ||||||
|  | 				valVal interface{} | ||||||
|  | 			) | ||||||
|  | 			switch keyKind { | ||||||
|  | 			case reflect.Bool: | ||||||
|  | 				keyVal, err = cast.ToBoolE(mapIter.Key()) | ||||||
|  | 			case reflect.String: | ||||||
|  | 				keyVal, err = cast.ToStringE(mapIter.Key()) | ||||||
|  | 			case reflect.Float32: | ||||||
|  | 				keyVal, err = cast.ToFloat32E(mapIter.Key()) | ||||||
|  | 			case reflect.Float64: | ||||||
|  | 				keyVal, err = cast.ToFloat64E(mapIter.Key()) | ||||||
|  | 			case reflect.Int8: | ||||||
|  | 				keyVal, err = cast.ToInt8E(mapIter.Key()) | ||||||
|  | 			case reflect.Int: | ||||||
|  | 				keyVal, err = cast.ToIntE(mapIter.Key()) | ||||||
|  | 			case reflect.Int16: | ||||||
|  | 				keyVal, err = cast.ToInt16E(mapIter.Key()) | ||||||
|  | 			case reflect.Int32: | ||||||
|  | 				keyVal, err = cast.ToInt32E(mapIter.Key()) | ||||||
|  | 			case reflect.Int64: | ||||||
|  | 				keyVal, err = cast.ToInt64E(mapIter.Key()) | ||||||
|  | 			case reflect.Uint8: | ||||||
|  | 				keyVal, err = cast.ToUint8E(mapIter.Key()) | ||||||
|  | 			case reflect.Uint: | ||||||
|  | 				keyVal, err = cast.ToUintE(mapIter.Key()) | ||||||
|  | 			case reflect.Uint16: | ||||||
|  | 				keyVal, err = cast.ToUint16E(mapIter.Key()) | ||||||
|  | 			case reflect.Uint32: | ||||||
|  | 				keyVal, err = cast.ToUint32E(mapIter.Key()) | ||||||
|  | 			case reflect.Uint64: | ||||||
|  | 				keyVal, err = cast.ToUint64E(mapIter.Key()) | ||||||
|  | 			} | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			switch valKind { | ||||||
|  | 			case reflect.Bool: | ||||||
|  | 				valVal, err = cast.ToBoolE(mapIter.Value()) | ||||||
|  | 			case reflect.String: | ||||||
|  | 				valVal, err = cast.ToStringE(mapIter.Value()) | ||||||
|  | 			case reflect.Float32: | ||||||
|  | 				valVal, err = cast.ToFloat32E(mapIter.Value()) | ||||||
|  | 			case reflect.Float64: | ||||||
|  | 				valVal, err = cast.ToFloat64E(mapIter.Value()) | ||||||
|  | 			case reflect.Int8: | ||||||
|  | 				valVal, err = cast.ToInt8E(mapIter.Value()) | ||||||
|  | 			case reflect.Int: | ||||||
|  | 				valVal, err = cast.ToIntE(mapIter.Value()) | ||||||
|  | 			case reflect.Int16: | ||||||
|  | 				valVal, err = cast.ToInt16E(mapIter.Value()) | ||||||
|  | 			case reflect.Int32: | ||||||
|  | 				valVal, err = cast.ToInt32E(mapIter.Value()) | ||||||
|  | 			case reflect.Int64: | ||||||
|  | 				valVal, err = cast.ToInt64E(mapIter.Value()) | ||||||
|  | 			case reflect.Uint8: | ||||||
|  | 				valVal, err = cast.ToUint8E(mapIter.Value()) | ||||||
|  | 			case reflect.Uint: | ||||||
|  | 				valVal, err = cast.ToUintE(mapIter.Value()) | ||||||
|  | 			case reflect.Uint16: | ||||||
|  | 				valVal, err = cast.ToUint16E(mapIter.Value()) | ||||||
|  | 			case reflect.Uint32: | ||||||
|  | 				valVal, err = cast.ToUint32E(mapIter.Value()) | ||||||
|  | 			case reflect.Uint64: | ||||||
|  | 				valVal, err = cast.ToUint64E(mapIter.Value()) | ||||||
|  | 			} | ||||||
|  | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			val.SetMapIndex(reflect.ValueOf(keyVal), reflect.ValueOf(valVal)) | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user