// GoLuaFunc converts an arbitrary Go function into a Lua-compatible GoFunction. // There are special optimized cases for functions that go from strings to strings, // and doubles to doubles, but otherwise Go // reflection is used to provide a generic wrapper function func GoLuaFunc(L *lua.State, fun interface{}) lua.GoFunction { switch f := fun.(type) { case func(*lua.State) int: return f case func(string) string: return func(L *lua.State) int { L.PushString(f(L.ToString(1))) return 1 } case func(float64) float64: return func(L *lua.State) int { L.PushNumber(f(L.ToNumber(1))) return 1 } default: } var funv reflect.Value switch ff := fun.(type) { case reflect.Value: funv = ff default: funv = valueOf(fun) } funt := funv.Type() targs, tout := functionArgRetTypes(funt) return func(L *lua.State) int { var lastT reflect.Type isVariadic := funt.IsVariadic() if isVariadic { lastT = targs[len(targs)-1].Elem() targs = targs[0 : len(targs)-1] } args := make([]reflect.Value, len(targs)) for i, t := range targs { val := LuaToGo(L, t, i+1) args[i] = valueOf(val) } if isVariadic { n := L.GetTop() for i := len(targs) + 1; i <= n; i++ { val := valueOf(LuaToGo(L, lastT, i)) args = append(args, val) } } resv := funv.Call(args) for i, val := range resv { GoToLua(L, tout[i], val) } return len(resv) } }