github.com/wfusion/gofusion@v1.1.14/common/utils/func.go (about)

     1  package utils
     2  
     3  import (
     4  	"reflect"
     5  	"regexp"
     6  	"runtime"
     7  
     8  	"github.com/gobwas/glob"
     9  	"github.com/mitchellh/mapstructure"
    10  )
    11  
    12  func GetFuncName(fn any) string {
    13  	return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
    14  }
    15  
    16  func WrapFunc(fn any) func(...any) {
    17  	return func(a ...any) {
    18  		runVariadicFunc(fn, a...)
    19  	}
    20  }
    21  
    22  func WrapFuncAny(fn any) func(...any) []any {
    23  	return func(a ...any) (b []any) {
    24  		ret := runVariadicFunc(fn, a...)
    25  		b = make([]any, 0, len(b))
    26  		for i := 0; i < len(ret); i++ {
    27  			b = append(b, ret[i].Interface())
    28  		}
    29  		return
    30  	}
    31  }
    32  
    33  func WrapFunc1[T any](fn any) func(...any) T {
    34  	return func(a ...any) (t T) {
    35  		ret := runVariadicFunc(fn, a...)
    36  		return ParseVariadicFuncResult[T](ret, 0)
    37  	}
    38  }
    39  
    40  // WrapFunc2 wrap a function with any number inputs and 2 generic type return,
    41  // return nothing if function has 0 outputs
    42  // return T1 if function only has 1 output
    43  // return function first output and last output if function has more than 2 outputs
    44  func WrapFunc2[T1, T2 any](fn any) func(...any) (T1, T2) {
    45  	return func(a ...any) (t1 T1, t2 T2) {
    46  		ret := runVariadicFunc(fn, a...)
    47  		t1 = ParseVariadicFuncResult[T1](ret, 0)
    48  		t2 = ParseVariadicFuncResult[T2](ret, 1)
    49  		return
    50  	}
    51  }
    52  
    53  func WrapFunc3[T1, T2, T3 any](fn any) func(...any) (T1, T2, T3) {
    54  	return func(a ...any) (t1 T1, t2 T2, t3 T3) {
    55  		ret := runVariadicFunc(fn, a...)
    56  		t1 = ParseVariadicFuncResult[T1](ret, 0)
    57  		t2 = ParseVariadicFuncResult[T2](ret, 1)
    58  		t3 = ParseVariadicFuncResult[T3](ret, 2)
    59  		return
    60  	}
    61  }
    62  
    63  func WrapFunc4[T1, T2, T3, T4 any](fn any) func(...any) (T1, T2, T3, T4) {
    64  	return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4) {
    65  		ret := runVariadicFunc(fn, a...)
    66  		t1 = ParseVariadicFuncResult[T1](ret, 0)
    67  		t2 = ParseVariadicFuncResult[T2](ret, 1)
    68  		t3 = ParseVariadicFuncResult[T3](ret, 2)
    69  		t4 = ParseVariadicFuncResult[T4](ret, 3)
    70  		return
    71  	}
    72  }
    73  
    74  func WrapFunc5[T1, T2, T3, T4, T5 any](fn any) func(...any) (T1, T2, T3, T4, T5) {
    75  	return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) {
    76  		ret := runVariadicFunc(fn, a...)
    77  		t1 = ParseVariadicFuncResult[T1](ret, 0)
    78  		t2 = ParseVariadicFuncResult[T2](ret, 1)
    79  		t3 = ParseVariadicFuncResult[T3](ret, 2)
    80  		t4 = ParseVariadicFuncResult[T4](ret, 3)
    81  		t5 = ParseVariadicFuncResult[T5](ret, 4)
    82  		return
    83  	}
    84  }
    85  
    86  func WrapFunc6[T1, T2, T3, T4, T5, T6 any](fn any) func(...any) (T1, T2, T3, T4, T5, T6) {
    87  	return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) {
    88  		ret := runVariadicFunc(fn, a...)
    89  		t1 = ParseVariadicFuncResult[T1](ret, 0)
    90  		t2 = ParseVariadicFuncResult[T2](ret, 1)
    91  		t3 = ParseVariadicFuncResult[T3](ret, 2)
    92  		t4 = ParseVariadicFuncResult[T4](ret, 3)
    93  		t5 = ParseVariadicFuncResult[T5](ret, 4)
    94  		t6 = ParseVariadicFuncResult[T6](ret, 5)
    95  		return
    96  	}
    97  }
    98  
    99  func WrapFunc7[T1, T2, T3, T4, T5, T6, T7 any](fn any) func(...any) (T1, T2, T3, T4, T5, T6, T7) {
   100  	return func(a ...any) (t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) {
   101  		ret := runVariadicFunc(fn, a...)
   102  		t1 = ParseVariadicFuncResult[T1](ret, 0)
   103  		t2 = ParseVariadicFuncResult[T2](ret, 1)
   104  		t3 = ParseVariadicFuncResult[T3](ret, 2)
   105  		t4 = ParseVariadicFuncResult[T4](ret, 3)
   106  		t5 = ParseVariadicFuncResult[T5](ret, 4)
   107  		t6 = ParseVariadicFuncResult[T6](ret, 5)
   108  		t7 = ParseVariadicFuncResult[T7](ret, 6)
   109  		return
   110  	}
   111  }
   112  
   113  func runVariadicFunc(fn any, a ...any) []reflect.Value {
   114  	var (
   115  		variadic   []reflect.Value
   116  		typ        = reflect.TypeOf(fn)
   117  		val        = reflect.ValueOf(fn)
   118  		numIn      = typ.NumIn()
   119  		isVariadic = typ.IsVariadic()
   120  	)
   121  
   122  	if isVariadic {
   123  		b := a[numIn-1:]
   124  		bt := typ.In(numIn - 1).Elem()
   125  		variadic = make([]reflect.Value, 0, len(b))
   126  		for _, param := range b {
   127  			paramVal := reflect.ValueOf(param)
   128  			if paramVal.CanConvert(bt) {
   129  				variadic = append(variadic, paramVal.Convert(bt))
   130  			} else {
   131  				bo := reflect.New(bt).Elem().Interface()
   132  				MustSuccess(mapstructure.Decode(param, &bo))
   133  				variadic = append(variadic, reflect.ValueOf(bo))
   134  			}
   135  		}
   136  		a = a[:numIn-1]
   137  	}
   138  
   139  	in := make([]reflect.Value, 0, len(a)+len(variadic))
   140  	for idx, param := range a {
   141  		pt := typ.In(idx)
   142  		paramVal := reflect.ValueOf(param)
   143  		if paramVal.CanConvert(pt) {
   144  			in = append(in, paramVal.Convert(pt))
   145  		} else {
   146  			po := reflect.New(pt).Elem().Interface()
   147  			MustSuccess(mapstructure.Decode(param, &po))
   148  			in = append(in, reflect.ValueOf(po))
   149  		}
   150  	}
   151  	in = append(in, variadic...)
   152  
   153  	return val.Call(in)
   154  }
   155  
   156  func ParseVariadicFuncResult[T any](rs []reflect.Value, idx int) (t T) {
   157  	var (
   158  		ok  bool
   159  		typ = reflect.TypeOf(t)
   160  	)
   161  	for i := idx; i < len(rs); i++ {
   162  		r := rs[i]
   163  		if !r.IsValid() || r.Type() == nil {
   164  			continue
   165  		}
   166  		if v := r.Interface(); v != nil {
   167  			if t, ok = v.(T); !ok && typ != nil && reflect.TypeOf(v).ConvertibleTo(typ) {
   168  				t = r.Convert(typ).Interface().(T)
   169  			}
   170  		}
   171  	}
   172  	return
   173  }
   174  
   175  type getCallerOption struct {
   176  	skipRegList        []*regexp.Regexp
   177  	skipGlobList       []glob.Glob
   178  	minimumCallerDepth int
   179  }
   180  
   181  func SkipRegexps(patterns ...string) OptionFunc[getCallerOption] {
   182  	return func(o *getCallerOption) {
   183  		for _, pattern := range patterns {
   184  			o.skipRegList = append(o.skipRegList, regexp.MustCompile(pattern))
   185  		}
   186  	}
   187  }
   188  
   189  func SkipGlobs(patterns ...string) OptionFunc[getCallerOption] {
   190  	return func(o *getCallerOption) {
   191  		for _, pattern := range patterns {
   192  			o.skipGlobList = append(o.skipGlobList, glob.MustCompile(pattern))
   193  		}
   194  	}
   195  }
   196  
   197  func SkipKnownDepth(minimumCallerDepth int) OptionFunc[getCallerOption] {
   198  	return func(o *getCallerOption) {
   199  		o.minimumCallerDepth = minimumCallerDepth
   200  	}
   201  }
   202  
   203  // GetCaller retrieves the name after stack skip
   204  func GetCaller(maximumCallerDepth int, opts ...OptionExtender) (frame *runtime.Frame) {
   205  	opt := ApplyOptions[getCallerOption](opts...)
   206  	pcs := make([]uintptr, maximumCallerDepth)
   207  	depth := runtime.Callers(opt.minimumCallerDepth, pcs)
   208  	frames := runtime.CallersFrames(pcs[:depth])
   209  outer:
   210  	for f, hasMore := frames.Next(); hasMore; f, hasMore = frames.Next() {
   211  		frame = &f
   212  
   213  		// If the caller isn't part of this package, we're done
   214  		for _, skipGlob := range opt.skipGlobList {
   215  			if skipGlob.Match(f.File) {
   216  				continue outer
   217  			}
   218  		}
   219  		for _, s := range opt.skipRegList {
   220  			if s.MatchString(f.File) {
   221  				continue outer
   222  			}
   223  		}
   224  		break
   225  	}
   226  
   227  	return
   228  }