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  }