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 }