Bump github.com/gookit/config/v2 from 2.2.3 to 2.2.4

Bumps [github.com/gookit/config/v2](https://github.com/gookit/config) from 2.2.3 to 2.2.4.
- [Release notes](https://github.com/gookit/config/releases)
- [Commits](https://github.com/gookit/config/compare/v2.2.3...v2.2.4)

---
updated-dependencies:
- dependency-name: github.com/gookit/config/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2023-11-03 10:26:28 +01:00
committed by Ralf Haferkamp
parent 30784affc4
commit 0df009eae0
141 changed files with 7314 additions and 4044 deletions
+32 -6
View File
@@ -27,11 +27,16 @@ func IsSimpleKind(k reflect.Kind) bool {
return k > reflect.Invalid && k <= reflect.Float64
}
// IsAnyInt check is intX or uintX type
// IsAnyInt check is intX or uintX type. alias of the IsIntLike()
func IsAnyInt(k reflect.Kind) bool {
return k >= reflect.Int && k <= reflect.Uintptr
}
// IsIntLike reports whether the type is int-like(intX, uintX).
func IsIntLike(k reflect.Kind) bool {
return k >= reflect.Int && k <= reflect.Uintptr
}
// IsIntx check is intX type
func IsIntx(k reflect.Kind) bool {
return k >= reflect.Int && k <= reflect.Int64
@@ -52,6 +57,17 @@ func IsNil(v reflect.Value) bool {
}
}
// CanBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
func CanBeNil(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
return true
case reflect.Struct:
return typ == reflectValueType
}
return false
}
// IsFunc value
func IsFunc(val any) bool {
if val == nil {
@@ -84,6 +100,9 @@ func IsEqual(src, dst any) bool {
return bytes.Equal(bs1, bs2)
}
// IsZero reflect value check, alias of the IsEmpty()
var IsZero = IsEmpty
// IsEmpty reflect value check
func IsEmpty(v reflect.Value) bool {
switch v.Kind() {
@@ -108,11 +127,17 @@ func IsEmpty(v reflect.Value) bool {
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
// IsEmptyValue reflect value check.
// Difference the IsEmpty(), if value is ptr, will check real elem.
// IsEmptyValue reflect value check, alias of the IsEmptyReal()
var IsEmptyValue = IsEmptyReal
// IsEmptyReal reflect value check.
//
// Note:
//
// Difference the IsEmpty(), if value is ptr or interface, will check real elem.
//
// From src/pkg/encoding/json/encode.go.
func IsEmptyValue(v reflect.Value) bool {
func IsEmptyReal(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
@@ -128,11 +153,12 @@ func IsEmptyValue(v reflect.Value) bool {
if v.IsNil() {
return true
}
return IsEmptyValue(v.Elem())
return IsEmptyReal(v.Elem())
case reflect.Func:
return v.IsNil()
case reflect.Invalid:
return true
}
return false
return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
+83 -23
View File
@@ -2,6 +2,7 @@ package reflects
import (
"fmt"
"math"
"reflect"
"strconv"
@@ -12,13 +13,19 @@ import (
)
// BaseTypeVal convert custom type or intX,uintX,floatX to generic base type.
func BaseTypeVal(v reflect.Value) (value any, err error) {
return ToBaseVal(v)
}
// ToBaseVal convert custom type or intX,uintX,floatX to generic base type.
//
// intX/unitX => int64
// intX => int64
// unitX => uint64
// floatX => float64
// string => string
//
// returns int64,string,float or error
func BaseTypeVal(v reflect.Value) (value any, err error) {
func ToBaseVal(v reflect.Value) (value any, err error) {
v = reflect.Indirect(v)
switch v.Kind() {
@@ -27,7 +34,7 @@ func BaseTypeVal(v reflect.Value) (value any, err error) {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
value = v.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
value = int64(v.Uint()) // always return int64
value = v.Uint() // always return int64
case reflect.Float32, reflect.Float64:
value = v.Float()
default:
@@ -36,14 +43,23 @@ func BaseTypeVal(v reflect.Value) (value any, err error) {
return
}
// ConvToType convert and create reflect.Value by give reflect.Type
func ConvToType(val any, typ reflect.Type) (rv reflect.Value, err error) {
return ValueByType(val, typ)
}
// ValueByType create reflect.Value by give reflect.Type
func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) {
// handle kind: string, bool, intX, uintX, floatX
if typ.Kind() == reflect.String || typ.Kind() <= reflect.Float64 {
return ValueByKind(val, typ.Kind())
return ConvToKind(val, typ.Kind())
}
newRv := reflect.ValueOf(val)
var ok bool
var newRv reflect.Value
if newRv, ok = val.(reflect.Value); !ok {
newRv = reflect.ValueOf(val)
}
// try auto convert slice type
if IsArrayOrSlice(newRv.Kind()) && IsArrayOrSlice(typ.Kind()) {
@@ -59,72 +75,116 @@ func ValueByType(val any, typ reflect.Type) (rv reflect.Value, err error) {
return
}
// ValueByKind create reflect.Value by give reflect.Kind
// ValueByKind convert and create reflect.Value by give reflect.Kind
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
return ConvToKind(val, kind)
}
// ConvToKind convert and create reflect.Value by give reflect.Kind
//
// TIPs:
//
// Only support kind: string, bool, intX, uintX, floatX
func ValueByKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
func ConvToKind(val any, kind reflect.Kind) (rv reflect.Value, err error) {
if rv, ok := val.(reflect.Value); ok {
val = rv.Interface()
}
switch kind {
case reflect.Int:
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
var dstV int
if dstV, err = mathutil.ToInt(val); err == nil {
rv = reflect.ValueOf(dstV)
}
case reflect.Int8:
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
var dstV int
if dstV, err = mathutil.ToInt(val); err == nil {
if dstV > math.MaxInt8 {
return rv, fmt.Errorf("value overflow int8. val: %v", val)
}
rv = reflect.ValueOf(int8(dstV))
}
case reflect.Int16:
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
var dstV int
if dstV, err = mathutil.ToInt(val); err == nil {
if dstV > math.MaxInt16 {
return rv, fmt.Errorf("value overflow int16. val: %v", val)
}
rv = reflect.ValueOf(int16(dstV))
}
case reflect.Int32:
if dstV, err1 := mathutil.ToInt(val); err1 == nil {
var dstV int
if dstV, err = mathutil.ToInt(val); err == nil {
if dstV > math.MaxInt32 {
return rv, fmt.Errorf("value overflow int32. val: %v", val)
}
rv = reflect.ValueOf(int32(dstV))
}
case reflect.Int64:
if dstV, err1 := mathutil.ToInt64(val); err1 == nil {
var dstV int64
if dstV, err = mathutil.ToInt64(val); err == nil {
rv = reflect.ValueOf(dstV)
}
case reflect.Uint:
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
rv = reflect.ValueOf(uint(dstV))
}
case reflect.Uint8:
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint8 {
return rv, fmt.Errorf("value overflow uint8. val: %v", val)
}
rv = reflect.ValueOf(uint8(dstV))
}
case reflect.Uint16:
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint16 {
return rv, fmt.Errorf("value overflow uint16. val: %v", val)
}
rv = reflect.ValueOf(uint16(dstV))
}
case reflect.Uint32:
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
if dstV > math.MaxUint32 {
return rv, fmt.Errorf("value overflow uint32. val: %v", val)
}
rv = reflect.ValueOf(uint32(dstV))
}
case reflect.Uint64:
if dstV, err1 := mathutil.ToUint(val); err1 == nil {
var dstV uint64
if dstV, err = mathutil.ToUint(val); err == nil {
rv = reflect.ValueOf(dstV)
}
case reflect.Float32:
if dstV, err1 := mathutil.ToFloat(val); err1 == nil {
var dstV float64
if dstV, err = mathutil.ToFloat(val); err == nil {
if dstV > math.MaxFloat32 {
return rv, fmt.Errorf("value overflow float32. val: %v", val)
}
rv = reflect.ValueOf(float32(dstV))
}
case reflect.Float64:
if dstV, err1 := mathutil.ToFloat(val); err1 == nil {
var dstV float64
if dstV, err = mathutil.ToFloat(val); err == nil {
rv = reflect.ValueOf(dstV)
}
case reflect.String:
if dstV, err1 := strutil.ToString(val); err1 == nil {
rv = reflect.ValueOf(dstV)
} else {
err = err1
}
case reflect.Bool:
if bl, err := comfunc.ToBool(val); err == nil {
if bl, err1 := comfunc.ToBool(val); err1 == nil {
rv = reflect.ValueOf(bl)
} else {
err = err1
}
}
if !rv.IsValid() {
default:
err = comdef.ErrConvType
}
return
+317
View File
@@ -0,0 +1,317 @@
package reflects
import (
"errors"
"fmt"
"reflect"
"github.com/gookit/goutil/basefn"
)
// FuncX wrap a go func. represent a function
type FuncX struct {
CallOpt
// Name of func. eg: "MyFunc"
Name string
// rv is the `reflect.Value` of func
rv reflect.Value
rt reflect.Type
}
// NewFunc instance. param fn support func and reflect.Value
func NewFunc(fn any) *FuncX {
var ok bool
var rv reflect.Value
if rv, ok = fn.(reflect.Value); !ok {
rv = reflect.ValueOf(fn)
}
rv = indirectInterface(rv)
if !rv.IsValid() {
panic("input func is nil")
}
typ := rv.Type()
if typ.Kind() != reflect.Func {
basefn.Panicf("non-function of type: %s", typ)
}
return &FuncX{rv: rv, rt: typ}
}
// NumIn get the number of func input args
func (f *FuncX) NumIn() int {
return f.rt.NumIn()
}
// NumOut get the number of func output args
func (f *FuncX) NumOut() int {
return f.rt.NumOut()
}
// Call the function with given arguments.
//
// Usage:
//
// func main() {
// fn := func(a, b int) int {
// return a + b
// }
//
// fx := NewFunc(fn)
// ret, err := fx.Call(1, 2)
// fmt.Println(ret[0], err) // Output: 3 <nil>
// }
func (f *FuncX) Call(args ...any) ([]any, error) {
// convert args to []reflect.Value
argRvs := make([]reflect.Value, len(args))
for i, arg := range args {
argRvs[i] = reflect.ValueOf(arg)
}
ret, err := f.CallRV(argRvs)
if err != nil {
return nil, err
}
// convert ret to []any
rets := make([]any, len(ret))
for i, r := range ret {
rets[i] = r.Interface()
}
return rets, nil
}
// Call2 returns the result of evaluating the first argument as a function.
// The function must return 1 result, or 2 results, the second of which is an error.
//
// - Only support func with 1 or 2 return values: (val) OR (val, err)
// - Will check args and try convert input args to func args type.
func (f *FuncX) Call2(args ...any) (any, error) {
// convert args to []reflect.Value
argRvs := make([]reflect.Value, len(args))
for i, arg := range args {
argRvs[i] = reflect.ValueOf(arg)
}
if f.TypeChecker == nil {
f.TypeChecker = OneOrTwoOutChecker
}
// do call func
ret, err := Call(f.rv, argRvs, &f.CallOpt)
if err != nil {
return emptyValue, err
}
// func return like: (val, err)
if len(ret) == 2 && !ret[1].IsNil() {
return ret[0].Interface(), ret[1].Interface().(error)
}
return ret[0].Interface(), nil
}
// CallRV call the function with given reflect.Value arguments.
func (f *FuncX) CallRV(args []reflect.Value) ([]reflect.Value, error) {
return Call(f.rv, args, &f.CallOpt)
}
// WithTypeChecker set type checker
func (f *FuncX) WithTypeChecker(checker TypeCheckerFn) *FuncX {
f.TypeChecker = checker
return f
}
// WithEnhanceConv set enhance convert
func (f *FuncX) WithEnhanceConv() *FuncX {
f.EnhanceConv = true
return f
}
// String of func
func (f *FuncX) String() string {
return f.rt.String()
}
// TypeCheckerFn type checker func
type TypeCheckerFn func(typ reflect.Type) error
// CallOpt call options
type CallOpt struct {
// TypeChecker check func type before call func. eg: check return values
TypeChecker TypeCheckerFn
// EnhanceConv try to enhance auto convert args to func args type
// - support more type: string, int, uint, float, bool
EnhanceConv bool
}
// OneOrTwoOutChecker check func type. only allow 1 or 2 return values
//
// Allow func returns:
// - 1 return: (value)
// - 2 return: (value, error)
var OneOrTwoOutChecker = func(typ reflect.Type) error {
if !good1or2outFunc(typ) {
return errors.New("func allow with 1 result or 2 results where the second is an error")
}
return nil
}
//
// TIP:
// flow func refer from text/template package.
//
//
// reports whether the function or method has the right result signature.
func good1or2outFunc(typ reflect.Type) bool {
// We allow functions with 1 result or 2 results where the second is an error.
switch {
case typ.NumOut() == 1:
return true
case typ.NumOut() == 2 && typ.Out(1) == errorType:
return true
}
return false
}
// Call2 returns the result of evaluating the first argument as a function.
// The function must return 1 result, or 2 results, the second of which is an error.
//
// - Only support func with 1 or 2 return values: (val) OR (val, err)
// - Will check args and try convert input args to func args type.
func Call2(fn reflect.Value, args []reflect.Value) (reflect.Value, error) {
ret, err := Call(fn, args, &CallOpt{
TypeChecker: OneOrTwoOutChecker,
})
if err != nil {
return emptyValue, err
}
// func return like: (val, err)
if len(ret) == 2 && !ret[1].IsNil() {
return ret[0], ret[1].Interface().(error)
}
return ret[0], nil
}
// Call returns the result of evaluating the first argument as a function.
//
// - Will check args and try convert input args to func args type.
//
// from text/template/funcs.go#call
func Call(fn reflect.Value, args []reflect.Value, opt *CallOpt) ([]reflect.Value, error) {
fn = indirectInterface(fn)
if !fn.IsValid() {
return nil, fmt.Errorf("call of nil")
}
typ := fn.Type()
if typ.Kind() != reflect.Func {
return nil, fmt.Errorf("non-function of type %s", typ)
}
if opt == nil {
opt = &CallOpt{}
}
if opt.TypeChecker != nil {
if err := opt.TypeChecker(typ); err != nil {
return nil, err
}
}
numIn := typ.NumIn()
var dddType reflect.Type
if typ.IsVariadic() {
if len(args) < numIn-1 {
return nil, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1)
}
dddType = typ.In(numIn - 1).Elem()
} else {
if len(args) != numIn {
return nil, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn)
}
}
// Convert each arg to the type of the function's arg.
argv := make([]reflect.Value, len(args))
for i, arg := range args {
arg = indirectInterface(arg)
// Compute the expected type. Clumsy because of variadic.
argType := dddType
if !typ.IsVariadic() || i < numIn-1 {
argType = typ.In(i)
}
var err error
if argv[i], err = prepareArg(arg, argType, opt.EnhanceConv); err != nil {
return nil, fmt.Errorf("arg %d: %w", i, err)
}
}
return SafeCall(fn, argv)
}
// SafeCall2 runs fun.Call(args), and returns the resulting value and error, if
// any. If the call panics, the panic value is returned as an error.
//
// NOTE: Only support func with 1 or 2 return values: (val) OR (val, err)
//
// from text/template/funcs.go#safeCall
func SafeCall2(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {
ret, err := SafeCall(fun, args)
if err != nil {
return reflect.Value{}, err
}
// func return like: (val, err)
if len(ret) == 2 && !ret[1].IsNil() {
return ret[0], ret[1].Interface().(error)
}
return ret[0], nil
}
// SafeCall runs fun.Call(args), and returns the resulting values, or an error.
// If the call panics, the panic value is returned as an error.
func SafeCall(fun reflect.Value, args []reflect.Value) (ret []reflect.Value, err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
err = e
} else {
err = fmt.Errorf("%v", r)
}
}
}()
ret = fun.Call(args)
return
}
// prepareArg checks if value can be used as an argument of type argType, and
// converts an invalid value to appropriate zero if possible.
func prepareArg(value reflect.Value, argType reflect.Type, enhanced bool) (reflect.Value, error) {
if !value.IsValid() {
if !CanBeNil(argType) {
return emptyValue, fmt.Errorf("value is nil; should be of type %s", argType)
}
value = reflect.Zero(argType)
}
if value.Type().AssignableTo(argType) {
return value, nil
}
// If the argument is an int-like type, and the value is an int-like type, auto-convert.
if IsIntLike(value.Kind()) && IsIntLike(argType.Kind()) && value.Type().ConvertibleTo(argType) {
value = value.Convert(argType)
return value, nil
}
// enhance convert value to argType, support more type: string, int, uint, float, bool
if enhanced {
return ValueByType(value.Interface(), argType)
}
return emptyValue, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
}
+83
View File
@@ -0,0 +1,83 @@
package reflects
import (
"reflect"
"strconv"
)
// EachMap process any map data
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) {
if fn == nil {
return
}
if mp.Kind() != reflect.Map {
panic("only allow map value data")
}
for _, key := range mp.MapKeys() {
fn(key, mp.MapIndex(key))
}
}
// EachStrAnyMap process any map data as string key and any value
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) {
EachMap(mp, func(key, val reflect.Value) {
fn(String(key), val.Interface())
})
}
// FlatFunc custom collect handle func
type FlatFunc func(path string, val reflect.Value)
// FlatMap process tree map to flat key-value map.
//
// Examples:
//
// {"top": {"sub": "value", "sub2": "value2"} }
// ->
// {"top.sub": "value", "top.sub2": "value2" }
func FlatMap(rv reflect.Value, fn FlatFunc) {
if fn == nil {
return
}
if rv.Kind() != reflect.Map {
panic("only allow flat map data")
}
flatMap(rv, fn, "")
}
func flatMap(rv reflect.Value, fn FlatFunc, parent string) {
for _, key := range rv.MapKeys() {
path := String(key)
if parent != "" {
path = parent + "." + path
}
fv := Indirect(rv.MapIndex(key))
switch fv.Kind() {
case reflect.Map:
flatMap(fv, fn, path)
case reflect.Array, reflect.Slice:
flatSlice(fv, fn, path)
default:
fn(path, fv)
}
}
}
func flatSlice(rv reflect.Value, fn FlatFunc, parent string) {
for i := 0; i < rv.Len(); i++ {
path := parent + "[" + strconv.Itoa(i) + "]"
fv := Indirect(rv.Index(i))
switch fv.Kind() {
case reflect.Map:
flatMap(fv, fn, path)
case reflect.Array, reflect.Slice:
flatSlice(fv, fn, path)
default:
fn(path, fv)
}
}
}
+15
View File
@@ -1,2 +1,17 @@
// Package reflects Provide extends reflect util functions.
package reflects
import (
"fmt"
"reflect"
)
var emptyValue = reflect.Value{}
var (
anyType = reflect.TypeOf((*any)(nil)).Elem()
errorType = reflect.TypeOf((*error)(nil)).Elem()
fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
reflectValueType = reflect.TypeOf((*reflect.Value)(nil)).Elem()
)
+61
View File
@@ -0,0 +1,61 @@
package reflects
import (
"fmt"
"reflect"
)
// MakeSliceByElem create a new slice by the element type.
//
// - elType: the type of the element.
// - returns: the new slice.
//
// Usage:
//
// sl := MakeSliceByElem(reflect.TypeOf(1), 10, 20)
// sl.Index(0).SetInt(10)
//
// // Or use reflect.AppendSlice() merge two slice
// // Or use `for` with `reflect.Append()` add elements
func MakeSliceByElem(elTyp reflect.Type, len, cap int) reflect.Value {
return reflect.MakeSlice(reflect.SliceOf(elTyp), len, cap)
}
// FlatSlice flatten multi-level slice to given depth-level slice.
//
// Example:
//
// FlatSlice([]any{ []any{3, 4}, []any{5, 6} }, 1) // Output: []any{3, 4, 5, 6}
//
// always return reflect.Value of []any. note: maybe flatSl.Cap != flatSl.Len
func FlatSlice(sl reflect.Value, depth int) reflect.Value {
items := make([]reflect.Value, 0, sl.Cap())
slCap := addSliceItem(sl, depth, func(item reflect.Value) {
items = append(items, item)
})
flatSl := reflect.MakeSlice(reflect.SliceOf(anyType), 0, slCap)
flatSl = reflect.Append(flatSl, items...)
return flatSl
}
func addSliceItem(sl reflect.Value, depth int, collector func(item reflect.Value)) (c int) {
for i := 0; i < sl.Len(); i++ {
v := Elem(sl.Index(i))
if depth > 0 {
if v.Kind() != reflect.Slice {
panic(fmt.Sprintf("depth: %d, the value of index %d is not slice", depth, i))
}
c += addSliceItem(v, depth-1, collector)
} else {
collector(v)
}
}
if depth == 0 {
c = sl.Cap()
}
return c
}
+29 -8
View File
@@ -2,21 +2,28 @@ package reflects
import "reflect"
// BKind base data kind type
type BKind uint
// BKind base data kind type, alias of reflect.Kind
//
// Diff with reflect.Kind:
// - Int contains all intX types
// - Uint contains all uintX types
// - Float contains all floatX types
// - Array for array and slice types
// - Complex contains all complexX types
type BKind = reflect.Kind
// base kinds
const (
// Int for all intX types
Int = BKind(reflect.Int)
Int = reflect.Int
// Uint for all uintX types
Uint = BKind(reflect.Uint)
Uint = reflect.Uint
// Float for all floatX types
Float = BKind(reflect.Float32)
Float = reflect.Float32
// Array for array,slice types
Array = BKind(reflect.Array)
Array = reflect.Array
// Complex for all complexX types
Complex = BKind(reflect.Complex64)
Complex = reflect.Complex64
)
// ToBaseKind convert reflect.Kind to base kind
@@ -39,7 +46,7 @@ func ToBKind(kind reflect.Kind) BKind {
return Array
default:
// like: string, map, struct, ptr, func, interface ...
return BKind(kind)
return kind
}
}
@@ -48,6 +55,10 @@ type Type interface {
reflect.Type
// BaseKind value
BaseKind() BKind
// RealType returns a ptr type's real type. otherwise, will return self.
RealType() reflect.Type
// SafeElem returns a type's element type. otherwise, will return self.
SafeElem() reflect.Type
}
type xType struct {
@@ -69,3 +80,13 @@ func TypeOf(v any) Type {
func (t *xType) BaseKind() BKind {
return t.baseKind
}
// RealType returns a ptr type's real type. otherwise, will return self.
func (t *xType) RealType() reflect.Type {
return TypeReal(t.Type)
}
// SafeElem returns the array, slice, chan, map type's element type. otherwise, will return self.
func (t *xType) SafeElem() reflect.Type {
return TypeElem(t.Type)
}
+63 -86
View File
@@ -7,28 +7,82 @@ import (
"unsafe"
)
// loopIndirect returns the item at the end of indirection, and a bool to indicate
// if it's nil. If the returned bool is true, the returned value's kind will be
// either a pointer or interface.
func loopIndirect(v reflect.Value) (rv reflect.Value, isNil bool) {
for ; v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface; v = v.Elem() {
if v.IsNil() {
return v, true
}
}
return v, false
}
// indirectInterface returns the concrete value in an interface value,
// or else the zero reflect.Value.
// That is, if v represents the interface value x, the result is the same as reflect.ValueOf(x):
// the fact that x was an interface value is forgotten.
func indirectInterface(v reflect.Value) reflect.Value {
if v.Kind() != reflect.Interface {
return v
}
if v.IsNil() {
return emptyValue
}
return v.Elem()
}
// Elem returns the value that the interface v contains
// or that the pointer v points to.
// or that the pointer v points to. otherwise, will return self
func Elem(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
if v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
return v.Elem()
}
// otherwise, will return self
return v
}
// Indirect like reflect.Indirect(), but can also indirect reflect.Interface
// Indirect like reflect.Indirect(), but can also indirect reflect.Interface. otherwise, will return self
func Indirect(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
if v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
return v.Elem()
}
// otherwise, will return self
return v
}
// Len get reflect value length
// UnwrapAny unwrap reflect.Interface value. otherwise, will return self
func UnwrapAny(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Interface {
return v.Elem()
}
if v.IsNil() {
return emptyValue
}
return v
}
// TypeReal returns a ptr type's real type. otherwise, will return self.
func TypeReal(t reflect.Type) reflect.Type {
if t.Kind() == reflect.Pointer {
return t.Elem()
}
return t
}
// TypeElem returns the array, slice, chan, map type's element type. otherwise, will return self.
func TypeElem(t reflect.Type) reflect.Type {
switch t.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
return t.Elem()
default:
return t
}
}
// Len get reflect value length. allow: intX, uintX, floatX, string, map, array, chan, slice.
//
// Note: (u)intX use width. float to string then calc len.
func Len(v reflect.Value) int {
v = reflect.Indirect(v)
@@ -128,80 +182,3 @@ func SetRValue(rv, val reflect.Value) {
rv.Set(val)
}
// EachMap process any map data
func EachMap(mp reflect.Value, fn func(key, val reflect.Value)) {
if fn == nil {
return
}
if mp.Kind() != reflect.Map {
panic("only allow map value data")
}
for _, key := range mp.MapKeys() {
fn(key, mp.MapIndex(key))
}
}
// EachStrAnyMap process any map data as string key and any value
func EachStrAnyMap(mp reflect.Value, fn func(key string, val any)) {
EachMap(mp, func(key, val reflect.Value) {
fn(String(key), val.Interface())
})
}
// FlatFunc custom collect handle func
type FlatFunc func(path string, val reflect.Value)
// FlatMap process tree map to flat key-value map.
//
// Examples:
//
// {"top": {"sub": "value", "sub2": "value2"} }
// ->
// {"top.sub": "value", "top.sub2": "value2" }
func FlatMap(rv reflect.Value, fn FlatFunc) {
if fn == nil {
return
}
if rv.Kind() != reflect.Map {
panic("only allow flat map data")
}
flatMap(rv, fn, "")
}
func flatMap(rv reflect.Value, fn FlatFunc, parent string) {
for _, key := range rv.MapKeys() {
path := String(key)
if parent != "" {
path = parent + "." + path
}
fv := Indirect(rv.MapIndex(key))
switch fv.Kind() {
case reflect.Map:
flatMap(fv, fn, path)
case reflect.Array, reflect.Slice:
flatSlice(fv, fn, path)
default:
fn(path, fv)
}
}
}
func flatSlice(rv reflect.Value, fn FlatFunc, parent string) {
for i := 0; i < rv.Len(); i++ {
path := parent + "[" + strconv.Itoa(i) + "]"
fv := Indirect(rv.Index(i))
switch fv.Kind() {
case reflect.Map:
flatMap(fv, fn, path)
case reflect.Array, reflect.Slice:
flatSlice(fv, fn, path)
default:
fn(path, fv)
}
}
}
+2 -3
View File
@@ -31,7 +31,7 @@ func ValueOf(v any) Value {
// Indirect value. alias of the reflect.Indirect()
func (v Value) Indirect() Value {
if v.Kind() != reflect.Ptr {
if v.Kind() != reflect.Pointer {
return v
}
@@ -46,9 +46,8 @@ func (v Value) Indirect() Value {
//
// TIP: not like reflect.Value.Elem. otherwise, will return self.
func (v Value) Elem() Value {
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
if v.Kind() == reflect.Pointer || v.Kind() == reflect.Interface {
elem := v.Value.Elem()
return Value{
Value: elem,
baseKind: ToBKind(elem.Kind()),