github.com/pubgo/xprocess@v0.1.11/xutil/util.go (about) 1 package xutil 2 3 import ( 4 "fmt" 5 "reflect" 6 "sync" 7 8 "github.com/pubgo/xerror" 9 ) 10 11 func FuncValue(fn interface{}) func(...reflect.Value) []reflect.Value { 12 xerror.Assert(fn == nil, "[fn] is nil") 13 14 vfn, ok := fn.(reflect.Value) 15 if !ok { 16 vfn = reflect.ValueOf(fn) 17 } 18 19 xerror.Assert(!vfn.IsValid() || vfn.Kind() != reflect.Func || vfn.IsNil(), "[fn] type error or nil") 20 21 var tfn = vfn.Type() 22 var numIn = tfn.NumIn() 23 var variadicType reflect.Type 24 var variadicValue reflect.Value 25 if tfn.IsVariadic() { 26 variadicType = tfn.In(numIn - 1) 27 variadicValue = reflect.Zero(variadicType) 28 if isElem(variadicType.Kind()) { 29 variadicValue = reflect.New(variadicType).Elem() 30 } 31 } 32 33 return func(args ...reflect.Value) []reflect.Value { 34 xerror.Assert(variadicType == nil && numIn != len(args) || variadicType != nil && len(args) < numIn-1, 35 "the input params of func is not match, func: %s, numIn:%d numArgs:%d\n", tfn, numIn, len(args)) 36 37 for i := range args { 38 // variadic 39 if i >= numIn && !args[i].IsValid() { 40 args[i] = variadicValue 41 continue 42 } 43 44 if !args[i].IsValid() { 45 args[i] = reflect.Zero(tfn.In(i)) 46 if isElem(args[i].Kind()) && args[i].IsNil() { 47 args[i] = reflect.New(tfn.In(i).Elem()) 48 } 49 continue 50 } 51 52 if isElem(args[i].Kind()) && args[i].IsNil() { 53 args[i] = reflect.Zero(tfn.In(i)) 54 } 55 } 56 57 defer xerror.RespRaise(func(err xerror.XErr) error { 58 valuePut(args) 59 return err.WrapF("[vfn.Call] panic, err:%#v, args:%s, fn:%s", err, valueStr(args...), tfn) 60 }) 61 62 return vfn.Call(args) 63 } 64 } 65 66 func FuncRaw(fn interface{}) func(...interface{}) []reflect.Value { 67 vfn := FuncValue(fn) 68 return func(args ...interface{}) []reflect.Value { 69 var args1 = valueGet() 70 for i := range args { 71 var vk reflect.Value 72 if args[i] == nil { 73 vk = reflect.ValueOf(args[i]) 74 } else if k1, ok := args[i].(reflect.Value); ok { 75 vk = k1 76 } else { 77 vk = reflect.ValueOf(args[i]) 78 } 79 args1 = append(args1, vk) 80 } 81 return vfn(args1...) 82 } 83 } 84 85 func Func(fn interface{}) func(...interface{}) func(...interface{}) { 86 vfn := FuncRaw(fn) 87 return func(args ...interface{}) func(...interface{}) { 88 ret := vfn(args...) 89 return func(fns ...interface{}) { 90 if len(fns) == 0 { 91 return 92 } 93 94 xerror.Assert(fns[0] == nil, "[fns] is nil") 95 96 cfn, ok := fns[0].(reflect.Value) 97 if !ok { 98 cfn = reflect.ValueOf(fns[0]) 99 } 100 101 xerror.Assert(!cfn.IsValid() || cfn.Kind() != reflect.Func || cfn.IsNil(), 102 "[fns] type error or nil") 103 104 tfn := reflect.TypeOf(fn) 105 xerror.Assert(cfn.Type().NumIn() != tfn.NumOut(), 106 "the input num and output num of the callback func is not match, [%d]<->[%d]\n", 107 cfn.Type().NumIn(), tfn.NumOut()) 108 109 xerror.Assert(cfn.Type().NumIn() != 0 && cfn.Type().In(0) != tfn.Out(0), 110 "the output type of the callback func is not match, [%s]<->[%s]\n", 111 cfn.Type().In(0), tfn.Out(0)) 112 113 defer xerror.RespRaise(func(err xerror.XErr) error { 114 valuePut(ret) 115 return err.WrapF("[cfn.Call] panic, err:%#v, args:%s, fn:%s", err, valueStr(ret...), cfn.Type()) 116 }) 117 118 cfn.Call(ret) 119 } 120 } 121 } 122 123 var valuePool = sync.Pool{New: func() interface{} { return make([]reflect.Value, 0, 1) }} 124 125 func valueGet() []reflect.Value { return valuePool.Get().([]reflect.Value) } 126 func valuePut(v []reflect.Value) { valuePool.Put(v[:0]) } 127 128 func valueStr(values ...reflect.Value) string { 129 var data []interface{} 130 for i := range values { 131 var val interface{} = nil 132 if values[i].IsValid() { 133 val = values[i].Interface() 134 } 135 data = append(data, val) 136 } 137 return fmt.Sprint(data...) 138 } 139 140 func isElem(val reflect.Kind) bool { 141 switch val { 142 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: 143 return true 144 } 145 return false 146 }