223 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package options
 | |
| 
 | |
| import (
 | |
| 	"reflect"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/spf13/cast"
 | |
| 	mreflect "go.unistack.org/micro/v4/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")
 | |
| )
 |