micro/options/options.go
Vasiliy Tolstov 9db34ad482
All checks were successful
lint / lint (pull_request) Successful in 3m4s
coverage / build (pull_request) Successful in 7m20s
test / test (pull_request) Successful in 3m14s
options: generic options funcs
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2025-01-14 18:42:29 +03:00

223 lines
5.0 KiB
Go

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")
)