func TemplateVars(typ interface{}) template.VarMap { fin := []reflect.Type{reflect.TypeOf(typ)} stringOut := []reflect.Type{reflect.TypeOf("")} stringFuncTyp := reflect.FuncOf(fin, stringOut, false) varFunc := func(in []reflect.Value) []reflect.Value { url, _ := updatesURL(in[0]) return []reflect.Value{reflect.ValueOf(url)} } boolOut := []reflect.Type{reflect.TypeOf(true)} boolFuncTyp := reflect.FuncOf(fin, boolOut, false) enabledFunc := func(in []reflect.Value) []reflect.Value { url, _ := updatesURL(in[0]) enabled := url != "" return []reflect.Value{reflect.ValueOf(enabled)} } template.AddFunc(&template.Func{ Name: "__gondola_is_live_reload_enabled", Fn: reflect.MakeFunc(boolFuncTyp, enabledFunc).Interface(), Traits: template.FuncTraitContext, }) reasonFunc := func(in []reflect.Value) []reflect.Value { _, reason := updatesURL(in[0]) return []reflect.Value{reflect.ValueOf(reason)} } template.AddFunc(&template.Func{ Name: "__gondola_is_live_reload_disabled_reason", Fn: reflect.MakeFunc(stringFuncTyp, reasonFunc).Interface(), Traits: template.FuncTraitContext, }) return template.VarMap{ "BroadcasterWebsocketUrl": reflect.MakeFunc(stringFuncTyp, varFunc).Interface(), } }
func MakeMockedWrapper(fptr interface{}) { var maker = func(in []reflect.Value) []reflect.Value { wrapper := in[0].Elem() client := in[1] wrapperType := wrapper.Type() for i := 1; i < wrapperType.NumField(); i++ { field := wrapper.Field(i) fd, ok := client.Type().MethodByName(wrapperType.Field(i).Name) if !ok { logs.Info("Reflect Failed") continue } fdt := fd.Type f := reflect.MakeFunc(field.Type(), func(in []reflect.Value) []reflect.Value { ret := make([]reflect.Value, 0, fdt.NumOut()) for i := 0; i < fdt.NumOut(); i++ { ret = append(ret, reflect.Zero(fdt.Out(i))) } return ret }) field.Set(f) } return []reflect.Value{in[0]} } fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), maker) fn.Set(v) }
func test16() { defer mustRecover(16) f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func())) f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func()) defer f2(f3) panic(16) }
// Funcs allows creating functions for easily setting and retrieving // values associated with a key from an Storage in a type safe manner. // // Getter functions must conform to the following specification: // // func(storage S, key interface{}) V or func(storage S, key interface{}) (V, bool) // // Where S is kvs.Storage or implements kvs.Storage and V is any type. // // Setter functions must conform to the following specification: // // func(storage S, key interface{}, value V) // // Where V is any type. Note that when generating a getter/setter function pair, // V must be exactly the same type in the getter and in the setter. // // See the examples for more information. // // Note that this function will panic if the prototypes of the functions don't, // match the expected ones. // // Alternatively, if you're only going to store once value per type, use // TypeFuncs instead. func Funcs(getter interface{}, setter interface{}) { gptr := reflect.ValueOf(getter) if gptr.Kind() != reflect.Ptr || gptr.Elem().Kind() != reflect.Func { panic(fmt.Errorf("getter must be a pointer to a function, not %v", gptr.Type())) } gval := gptr.Elem() gvalType := gval.Type() if gvalType.NumIn() != 2 { panic(fmt.Errorf("getter must accept two arguments, not %d", gvalType.NumIn())) } if !isStorageType(gvalType.In(0)) { panic(fmt.Errorf("getter 1st argument must be of type %v or assignable to it, not %v", storageType, gvalType.In(0))) } if gvalType.In(1) != emptyInterfaceType { panic(fmt.Errorf("getter 2nd argument must be of type %v, not %v", emptyInterfaceType, gvalType.In(1))) } if gvalType.NumOut() != 1 { panic(fmt.Errorf("getter must return only one value, not %d", gvalType.NumOut())) } ttype := gvalType.Out(0) gval.Set(reflect.MakeFunc(gvalType, storageGetKey(ttype))) sptr := reflect.ValueOf(setter) if sptr.Kind() != reflect.Ptr || sptr.Elem().Kind() != reflect.Func { panic(fmt.Errorf("setter must be a pointer to a function, not %v", sptr.Type())) } sval := sptr.Elem() svalType := sval.Type() if svalType.NumIn() != 3 { panic(fmt.Errorf("setter must accept three arguments, not %d", svalType.NumIn())) } if !isStorageType(svalType.In(0)) { panic(fmt.Errorf("setter's 1st argument must be of type %v or assignable to it, not %v", storageType, svalType.In(0))) } if svalType.In(1) != emptyInterfaceType { panic(fmt.Errorf("setter's 2nd argument must be of type %v, not %v", emptyInterfaceType, svalType.In(1))) } if svalType.In(2) != ttype { panic(fmt.Errorf("setter's 3rd argument must be of type %v (to match getter), not %v", ttype, svalType.In(2))) } if svalType.NumOut() != 0 { panic(fmt.Errorf("setter not return any values, not %d", svalType.NumOut())) } sval.Set(reflect.MakeFunc(svalType, storageSetKey)) }
func (self *GoSpy) setTargetFn(fn func(args []reflect.Value) []reflect.Value) { targetType := self.mock.GetTarget().Type() wrapperFn := func(args []reflect.Value) []reflect.Value { self.storeCall(args) return reflect.MakeFunc(targetType, fn).Call(args) } targetFn := reflect.MakeFunc(targetType, wrapperFn) self.mock.Replace(targetFn.Interface()) }
func makeSum(fptr interface{}) { fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), sum) fn.Set(v) }
// compose modifies t such that it respects the previously-registered hooks in old, // subject to the composition policy requested in t.Compose. func (t *ClientTrace) compose(old *ClientTrace) { if old == nil { return } tv := reflect.ValueOf(t).Elem() ov := reflect.ValueOf(old).Elem() structType := tv.Type() for i := 0; i < structType.NumField(); i++ { tf := tv.Field(i) hookType := tf.Type() if hookType.Kind() != reflect.Func { continue } of := ov.Field(i) if of.IsNil() { continue } if tf.IsNil() { tf.Set(of) continue } // Make a copy of tf for tf to call. (Otherwise it // creates a recursive call cycle and stack overflows) tfCopy := reflect.ValueOf(tf.Interface()) // We need to call both tf and of in some order. newFunc := reflect.MakeFunc(hookType, func(args []reflect.Value) []reflect.Value { tfCopy.Call(args) return of.Call(args) }) tv.Field(i).Set(newFunc) } }
// One wraps the given function to require one less argument, passing in the // given value instead. The value MUST NOT be nil. // // BUG(abg): Variadic functions are not supported. func One(f interface{}, a interface{}) interface{} { if f == nil { panic("f is required") } if a == nil { panic("a is required and cannot be nil") } fType := reflect.TypeOf(f) if fType.Kind() != reflect.Func { panic(fmt.Sprintf("%v (%v) is not a function", f, fType)) } if fType.IsVariadic() { panic(fmt.Sprintf("%v (%v) is variadic", f, fType)) } in := args(fType) out := returns(fType) if len(in) == 0 { panic(fmt.Sprintf("%v (%v) does not accept enough arguments to curry in %v", f, fType, a)) } fVal := reflect.ValueOf(f) aVal := reflect.ValueOf(a) newFType := reflect.FuncOf(in[1:], out, false) return reflect.MakeFunc(newFType, func(args []reflect.Value) []reflect.Value { newArgs := make([]reflect.Value, 0, fType.NumIn()) newArgs = append(newArgs, aVal) newArgs = append(newArgs, args...) return fVal.Call(newArgs) }).Interface() }
// Open retrieves the symbols defined in plugin, from the shared library at path. // path should omit the file extension (e.g. "plugin" instead of "plugin.so"). // plugin should be a pointer to a struct embedding the Plugin struct. func Open(plugin interface{}, path string) error { v := reflect.ValueOf(plugin) t := v.Type() if t.Kind() != reflect.Ptr { return errors.New("Open expects a plugin to be a pointer to a struct") } v = v.Elem() t = v.Type() if t.Kind() != reflect.Struct { return errors.New("Open expects a plugin to be a pointer to a struct") } lib, err := dl.Open(path, 0) if err != nil { return err } for i := 0; i < v.NumField(); i++ { tf := t.Field(i) if tf.Name != _plugin { sym := v.Field(i).Interface() if err := lib.Sym(tf.Name, &sym); err != nil && tf.Type.Kind() == reflect.Func { fn := reflect.MakeFunc(tf.Type, nopFn) v.Field(i).Set(fn) } else { v.Field(i).Set(reflect.ValueOf(sym)) } } else { p := Plugin{lib} v.Field(i).Set(reflect.ValueOf(p)) } } return nil }
func function2Func(in *reflect.Value, t reflect.Type) { fn := in.MethodByName("Call") wrap := func(args []reflect.Value) (results []reflect.Value) { ret := fn.Call(args)[0] n := t.NumOut() if n == 0 { return } if n == 1 { if t.Out(0) != typeIntf { ret = ret.Elem() } return []reflect.Value{ret} } if ret.Kind() != reflect.Slice || ret.Len() != n { panic(fmt.Sprintf("unexpected return value count, we need `%d` values", n)) } results = make([]reflect.Value, n) for i := 0; i < n; i++ { result := ret.Index(i) if t.Out(i) != typeIntf { result = result.Elem() } results[i] = result } return } *in = reflect.MakeFunc(t, wrap) }
func getPluginProxy(name string, extInterface interface{}) interface{} { extInterfaceType := reflect.TypeOf(extInterface).Elem() if !hasImplementation(name, extInterfaceType.Name()) { return nil } pluginProxy := reflect.New(extInterfaceType).Elem() // loop over fields defined in extInterfaceType, // replacing them in v with implementations for i, n := 0, extInterfaceType.NumField(); i < n; i++ { field := pluginProxy.Field(i) structField := extInterfaceType.Field(i) newFunc := func(args []reflect.Value) []reflect.Value { runner := plugin.loaded[name] if runner == nil { return []reflect.Value{reflect.ValueOf(nil)} } value, err := runner.CallPlugin(name, structField.Name, convertArgs(args)) if err != nil { log.Println("plugins:", err) } if value != nil { return []reflect.Value{reflect.ValueOf(value)} } return []reflect.Value{} } field.Set(reflect.MakeFunc(field.Type(), newFunc)) } return pluginProxy.Interface() }
func main() { // swap is the implementation passed to MakeFunc. // It must work in terms of reflect.Values so that it is possible // to write code without knowing beforehand what the types // will be. swap := func(in []reflect.Value) []reflect.Value { return []reflect.Value{in[1], in[0]} } // makeSwap expects fptr to be a pointer to a nil function. // It sets that pointer to a new function created with MakeFunc. // When the function is invoked, reflect turns the arguments // into Values, calls swap, and then turns swap's result slice // into the values returned by the new function. makeSwap := func(fptr interface{}) { // fptr is a pointer to a function. // Obtain the function value itself (likely nil) as a reflect.Value // so that we can query its type and then set the value. fn := reflect.ValueOf(fptr).Elem() // Make a function of the right type. v := reflect.MakeFunc(fn.Type(), swap) // Assign it to the value fn represents. fn.Set(v) } // Make and call a swap function for ints. var intSwap func(int, int) (int, int) makeSwap(&intSwap) fmt.Println(intSwap(0, 1)) // Make and call a swap function for float64s. var floatSwap func(float64, float64) (float64, float64) makeSwap(&floatSwap) fmt.Println(floatSwap(2.72, 3.14)) }
// 连接函数 返回error 结束 下一次传递 func JoinBy(t interface{}, fs ...interface{}) interface{} { val := reflect.ValueOf(t) if val.Kind() != reflect.Func { return nil } for k, v := range fs { c := toCaller(v) if c == nil { return nil } fs[k] = c } typ := val.Type() r := reflect.MakeFunc(typ, func(args []reflect.Value) (results []reflect.Value) { inj := inject.New() for _, v := range args { inj.Set(v.Type(), v) } inj = SliceFunc(inj, fs) for i := 0; i != typ.NumOut(); i++ { results = append(results, inj.Get(typ.Out(i))) } return }) return r.Interface() }
func (c *Client) MakeRpc(rpcName string, fptr interface{}) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("make rpc error") } }() fn := reflect.ValueOf(fptr).Elem() nOut := fn.Type().NumOut() if nOut == 0 || fn.Type().Out(nOut-1).Kind() != reflect.Interface { err = fmt.Errorf("%s return final output param must be error interface", rpcName) return } _, b := fn.Type().Out(nOut - 1).MethodByName("Error") if !b { err = fmt.Errorf("%s return final output param must be error interface", rpcName) return } f := func(in []reflect.Value) []reflect.Value { return c.call(fn, rpcName, in) } v := reflect.MakeFunc(fn.Type(), f) fn.Set(v) return }
func (p *AOP) GetProxy(beanID string) (proxy *Proxy, err error) { var bean *Bean if bean, err = p.beanFactory.GetBean(beanID); err != nil { return } tmpProxy := NewProxy(beanID) beanValue := reflect.ValueOf(bean.instance) beanType := reflect.TypeOf(bean.instance) for i := 0; i < beanValue.NumMethod(); i++ { methodV := beanValue.Method(i) methodT := beanType.Method(i) mType := methodV.Type() var metadata MethodMetadata if metadata, err = getMethodMetadata(methodT); err != nil { return } newFunc := p.funcWrapper(bean, metadata.Method.Name, mType) funcV := reflect.MakeFunc(mType, newFunc) metadata.Method.Func = funcV // rewrite to new proxy func tmpProxy.registryFunc(metadata) } proxy = tmpProxy return }
func init() { makeFunc := func(base func([]reflect.Value) []reflect.Value, fptr interface{}) { fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), base) fn.Set(v) } // getAll(Repository) (int, string) getAll := func(in []reflect.Value) []reflect.Value { values := in[0].MethodByName("GetAll").Call([]reflect.Value{}) // values is []reflect.Value returned by reflect.Call. // Since GetAll only returns interface{}, we just want the first object in values jsonResponse := string(jsonEncode(values[0].Interface())) return genericHandlerReturn(http.StatusFound, jsonResponse) } makeFunc(getAll, &GetAllUnits) /*func AddUnit(rw http.ResponseWriter, u Unit, repo IUnitRepository) (int, string) { repo.Add(&u) rw.Header().Set("Location", fmt.Sprintf("/unit/%d", u.Id)) return http.StatusCreated, "" } // add(http.ResponseWriter, entity, Repository) (int, string) add := func(in []reflect.Value) []reflect.Value { in[2].MethodByName("Add").Call([]reflect.Value{in[1]}) header := in[0].MethodByName("Header").Call(nil) location := reflect.ValueOf("Location") locationValue := reflect.ValueOf(fmt.Sprintf("/unit/%d", in[1].FieldByName("Id"))) reflect.ValueOf(header).MethodByName("Set").Call([]reflect.Value{location, locationValue}) return genericHandlerReturn(http.StatusCreated, "") } makeFunc(add, &AddUnit) */ // get(martini.Params, Repository) (int, string) get := func(in []reflect.Value) []reflect.Value { params := in[0].Interface().(martini.Params) id, err := strconv.Atoi(params["id"]) if err != nil { return notFoundGeneric() } inGet := []reflect.Value{reflect.ValueOf(id)} values := in[1].MethodByName("Get").Call(inGet) if values[0].IsNil() { return notFoundGeneric() } jsonResponse := string(jsonEncode(values[0].Interface())) return []reflect.Value{reflect.ValueOf(http.StatusOK), reflect.ValueOf(jsonResponse)} } makeFunc(get, &GetUnit) }
func makeSwap(fptr interface{}) { swap := func(in []reflect.Value) []reflect.Value { return []reflect.Value{in[1], in[0]} } fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), swap) fn.Set(v) }
func (self *ARC) Clone(p interface{}, nilfunc interface{}) { atomic.AddInt32(&self.count, 1) funcType := reflect.TypeOf(nilfunc) funcImpl := func(args []reflect.Value) []reflect.Value { c := atomic.AddInt32(&self.count, -1) self.cb(c) return nil } runtime.SetFinalizer(p, reflect.MakeFunc(funcType, funcImpl).Interface()) }
// asSingleton wraps funcValue (which must of type.Kind Func, and take no parameters) in a function which only // calls funcValue once, and caches the returned value for future calls. func asSingleton(funcValue reflect.Value) reflect.Value { var once sync.Once var cache []reflect.Value return reflect.MakeFunc(funcValue.Type(), func(args []reflect.Value) []reflect.Value { once.Do(func() { cache = funcValue.Call([]reflect.Value{}) }) return cache }) }
func main() { var hello func() // 함수를 담을 변수 선언 fn := reflect.ValueOf(&hello).Elem() // hello의 주소를 넘긴 뒤 Elem으로 값 정보를 가져옴 v := reflect.MakeFunc(fn.Type(), h) // h의 함수 정보를 생성 fn.Set(v) // hello의 값 정보인 fn에 h의 함수 정보 v를 설정하여 함수를 연결 hello() }
func Bind(dst interface{}, ver int, src interface{}) { dstFn := reflect.ValueOf(dst).Elem() srcFn := reflect.ValueOf(src) if dstFn.Type() != srcFn.Type() { panic("src and dst function types not identical") } proxy := reflect.MakeFunc(dstFn.Type(), func(in []reflect.Value) []reflect.Value { return lookupOrCall(srcFn, in) }) dstFn.Set(proxy) }
//take the value of emptyBodyFunction and sets swap function as function body implementation func (cacheSpot CacheSpot) setSwapAsFunctionBody() { //recover the value for function in the pointer fn := reflect.ValueOf(cacheSpot.CachedFunc).Elem() //put a recently created swap function as a function body for the emptyBodyFunction fn.Set(reflect.MakeFunc(fn.Type(), cacheSpot.swapFunction)) // Creating cache spot for Swap aop.FindOneType to calling aop.FindOneCustomer log.Debug("Creating cache spot: %v->(cache return)->%v ", cacheSpot.cachedFuncName, cacheSpot.hotFunctName) }
// makeSwap expects fptr to be a pointer to a nil function. // It sets that pointer to a new function created with MakeFunc. // When the function is invoked, reflect turns the arguments // into Values, calls swap, and then turns swap's result slice // into the values returned by the new function. func makeSwap(fptr interface{}) { // fptr is a pointer to a function. // Obtain the function value itself (likely nil) as a reflect.Value // so that we can query its type and then set the value. fn := reflect.ValueOf(fptr).Elem() // Make a function of the right type. v := reflect.MakeFunc(fn.Type(), swap) // Assign it to the value fn represents. fn.Set(v) }
func (a *Application) FinishLoad() { // handle defs / impls for name, info := range a.defs { fnPtr := info.ptr impls := a.impls[name] if len(impls) == 0 { panic(sp("no implementation for %s", name)) } fnType := reflect.TypeOf(fnPtr).Elem() for _, impl := range impls { if t := reflect.TypeOf(impl); t != fnType { panic(sp("defined %v, implemented %v", fnType, t)) } } handler, ok := fnHandlers[fnType] if ok { handler(fnPtr, impls) } else { implValues := make([]reflect.Value, 0, len(impls)) for _, impl := range impls { implValues = append(implValues, reflect.ValueOf(impl)) } reflect.ValueOf(fnPtr).Elem().Set(reflect.MakeFunc(fnType, func(args []reflect.Value) (ret []reflect.Value) { for _, impl := range implValues { impl.Call(args) } return })) } if info.provides { a.provides[name] = reflect.ValueOf(fnPtr).Elem().Interface() } } // match provides and requires for name, provide := range a.provides { requires := a.requires[name] provideValue := reflect.ValueOf(provide) for _, require := range requires { requireValue := reflect.ValueOf(require).Elem() if provideValue.Type() != requireValue.Type() { panic(sp("%s not match, %v provided, %v required", name, provideValue.Type(), requireValue.Type())) } requireValue.Set(provideValue) } delete(a.requires, name) } for name, _ := range a.requires { panic(sp("%s not provided", name)) } }
func (fi *FieldInfo) validateKeyField() error { if fi.KeyField == "" { return nil } if fi.ElemType == nil { return nil } if err := validateName(fi.KeyField); err != nil { return err } if fi.ElemType.Kind() != reflect.Struct { return errors.Errorf("element type %s not supported; must be struct", fi.ElemType) } if fi.KeyType.Kind() != reflect.String { return errors.Errorf("key type %s not supported; must be string", fi.KeyType) } elemKeyField, ok := fi.ElemType.FieldByName(fi.KeyField) if !ok { return errors.Errorf("%s has no field %q", fi.ElemType, fi.KeyField) } if elemKeyField.Type != fi.KeyType { return errors.Errorf("%s.%s is %s; want %s (from %s)", fi.ElemType, elemKeyField.Name, elemKeyField.Type, fi.KeyType, fi.Type) } getFuncType := reflect.FuncOf([]reflect.Type{fi.ElemType}, []reflect.Type{fi.KeyType}, false) ptrToElem := reflect.PtrTo(fi.ElemType) setFuncType := reflect.FuncOf([]reflect.Type{ptrToElem, fi.KeyType}, nil, false) fi.GetKeyFunc = reflect.MakeFunc(getFuncType, func(in []reflect.Value) []reflect.Value { return []reflect.Value{in[0].FieldByName(fi.KeyField)} }) fi.SetKeyFunc = reflect.MakeFunc(setFuncType, func(in []reflect.Value) []reflect.Value { elem := in[0].Elem() if !elem.IsValid() { return nil } in[0].Elem().FieldByName(fi.KeyField).Set(in[1]) return nil }) return nil }
func main() { var hello func() fn := reflect.ValueOf(&hello).Elem() v := reflect.MakeFunc(fn.Type(), h) fn.Set(v) hello() }
func DaynamicFuncPrac11() { var hello func() // 함수 담을 변수 선언 fn := reflect.ValueOf(&hello).Elem() // hello 주소 넘김 뒤 Elem으로 값 정보 v := reflect.MakeFunc(fn.Type(), h) // h함수 정보 생성 fn.Set(v) // hello 값 정보 fn에 h의 함수 정보 v를 설정하여 함수 연결 hello() }
func (q *quangoMatcher) Match(userPredicate interface{}) (successfulMatch bool, matchErr error) { typeOfPredicate := reflect.TypeOf(userPredicate) if typeOfPredicate.Kind() != reflect.Func { return false, fmt.Errorf("Expected a function, not a %s", typeOfPredicate) } cleanedPredicate := userPredicate if typeOfPredicate.NumOut() == 0 { predicateValue := reflect.ValueOf(userPredicate) predicateWrapper := func(args []reflect.Value) (returnVals []reflect.Value) { returnVals = []reflect.Value{reflect.ValueOf(true)} defer func() { err := recover() if err != nil { returnVals = []reflect.Value{reflect.ValueOf(false)} } }() predicateValue.Call(args) return } inType := []reflect.Type{} for i := 0; i < typeOfPredicate.NumIn(); i++ { inType = append(inType, typeOfPredicate.In(i)) } predicateType := reflect.FuncOf(inType, []reflect.Type{reflect.TypeOf(true)}, false) cleanedPredicate = reflect.MakeFunc(predicateType, predicateWrapper).Interface() } err := quick.Check(cleanedPredicate, nil) q.counterexample = "False" if err != nil { cerr, ok := err.(*quick.CheckError) if !ok { return false, err } q.counterexample = fmt.Sprintf("%s", cerr) return false, nil } return true, nil }
func Mock(targetFnPtr interface{}) (controller *MockController) { targetFn := reflect.ValueOf(targetFnPtr).Elem() controller = &MockController{ counter: make(chan int), callStack: make(chan map[int]*call), } go func() { controller.callStack <- make(map[int]*call) }() go func() { controller.counter <- 0 }() controller.targetFunc = targetFn targetFnType := targetFn.Type() numberOfOuts := targetFnType.NumOut() controller.originalFunc = reflect.ValueOf(targetFn.Interface()) for i := 0; i < numberOfOuts; i++ { controller.defaultYield = append(controller.defaultYield, reflect.Zero(targetFnType.Out(i))) } mockFn := reflect.MakeFunc(targetFnType, func(inValueSlice []reflect.Value) (yield []reflect.Value) { callCount := controller.incrementCounter() theCall := controller.NthCall(callCount - 1) var param []interface{} for i := 0; i < targetFnType.NumIn(); i++ { param = append(param, inValueSlice[i].Interface()) } theCall.updateParam(param) if numberOfOuts == len(theCall.yield) { // if user has set the return values the spit them out for i := 0; i < numberOfOuts; i++ { yield = append(yield, sanitizeReturn( targetFnType.Out(i), theCall.yield[i])) } } else { yield = controller.defaultYield } return yield }, ) targetFn.Set(mockFn) return controller }
// Memoize takes a function and returns a function of the same type. The // returned function remembers the return value(s) of the function call. // Any pointer values will be used as an address, so functions that modify // their arguments or programs that modify returned values will not work. // // The returned function is safe to call from multiple goroutines if the // original function is. Panics are handled, so calling panic from a function // will call panic with the same value on future invocations with the same // arguments. // // The arguments to the function must be of comparable types. Slices, maps, // functions, and structs or arrays that contain slices, maps, or functions // cause a runtime panic if they are arguments to a memoized function. // See also: https://golang.org/ref/spec#Comparison_operators // // As a special case, variadic functions (func(x, y, ...z)) are allowed. func Memoize(fn interface{}) interface{} { v := reflect.ValueOf(fn) t := v.Type() keyType := reflect.ArrayOf(t.NumIn(), interfaceType) cache := reflect.MakeMap(reflect.MapOf(keyType, valueType)) var mtx sync.Mutex return reflect.MakeFunc(t, func(args []reflect.Value) (results []reflect.Value) { key := reflect.New(keyType).Elem() for i, v := range args { if i == len(args)-1 && t.IsVariadic() { a := reflect.New(reflect.ArrayOf(v.Len(), v.Type().Elem())).Elem() for j, l := 0, v.Len(); j < l; j++ { a.Index(j).Set(v.Index(j)) } v = a } vi := v.Interface() key.Index(i).Set(reflect.ValueOf(&vi).Elem()) } mtx.Lock() val := cache.MapIndex(key) if val.IsValid() { mtx.Unlock() c := val.Interface().(*call) <-c.wait if c.panicked.IsValid() { panic(c.panicked.Interface()) } return c.results } w := make(chan struct{}) c := &call{wait: w} cache.SetMapIndex(key, reflect.ValueOf(c)) mtx.Unlock() panicked := true defer func() { if panicked { p := recover() c.panicked = reflect.ValueOf(p) close(w) panic(p) } }() if t.IsVariadic() { results = v.CallSlice(args) } else { results = v.Call(args) } panicked = false c.results = results close(w) return }).Interface() }