Skip to content

Instantly share code, notes, and snippets.

@jonocole
Created May 11, 2020 08:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonocole/1e6e8688459786305fe6770a7b73ccd5 to your computer and use it in GitHub Desktop.
Save jonocole/1e6e8688459786305fe6770a7b73ccd5 to your computer and use it in GitHub Desktop.
package main
import (
"reflect"
)
func WrapMethod(method, target interface{}) interface{} {
// 1. Inspect the method signature so that a
// replica can be returned
methodType := reflect.TypeOf(method)
// Collect method's input parameters, ignoring the first
// which is the receiver.
inTypes := []reflect.Type{}
for i := 1; i < methodType.NumIn(); i++ {
inTypes = append(inTypes, methodType.In(i))
}
// Collect method's output parameters
outTypes := []reflect.Type{}
for i := 0; i < methodType.NumOut(); i++ {
outTypes = append(outTypes, methodType.Out(i))
}
// 2. Return a new replica method which will
// use the value at the target address as
// the receiver when called
evalMethodType := reflect.FuncOf(inTypes, outTypes, methodType.IsVariadic())
return reflect.MakeFunc(evalMethodType, func(in []reflect.Value) []reflect.Value {
method := reflect.ValueOf(method)
// Set the first input arg as the receiver at the target address
args := append([]reflect.Value{reflect.ValueOf(target).Elem()}, in...)
// Call the wrapped method using the variadic form
// if the method is variadic
if methodType.IsVariadic() {
return method.CallSlice(args)
} else {
return method.Call(args)
}
}).Interface()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment