#ifndef LUABINDER_H #define LUABINDER_H #include "luavalue.h" #include "luastate.h" namespace luabinder { // transform const T& -> T template struct remove_const_ref { typedef typename std::remove_const::type>::type type; }; // pack an value into tuple recursively template struct pack_values_into_tuple { template static void call(Tuple& tuple, LuaState* lua) { typedef typename std::tuple_element::type ValueType; std::get(tuple) = safe_luavalue_cast(lua->popValue()); pack_values_into_tuple::call(tuple, lua); } }; template<> struct pack_values_into_tuple<0> { template static void call(Tuple &tuple, LuaState* lua) { } }; // call function template typename std::enable_if::value, int>::type call_fun_and_push_result(const F& f, LuaState* lua, Args... args) { Ret ret = f(args...); lua->pushValue(safe_to_luavalue(ret)); return 1; } // call function with no return template typename std::enable_if::value, int>::type call_fun_and_push_result(const F& f, LuaState* lua, Args... args) { f(args...); return 0; } // expand function arguments for calling template struct expand_fun_arguments { template static int call(const Tuple& tuple, const F& f, LuaState* lua, Args... args) { return expand_fun_arguments::call(tuple, f, lua, std::cref(std::get(tuple)), args...); } }; template struct expand_fun_arguments<0,Ret> { template static int call(const Tuple& tuple, const F& f, LuaState* lua, Args... args) { return call_fun_and_push_result(f, lua, args...); } }; // bind different types of functions template LuaCppFunction bind_fun_specializer(const F& f) { enum { N = std::tuple_size::value }; return [=](LuaState* lua) { if(lua->stackSize() != N) throw LuaBadNumberOfArgumentsException(N, lua->stackSize()); Tuple tuple; pack_values_into_tuple::call(tuple, lua); return expand_fun_arguments::call(tuple, f, lua); }; } // bind a std::function template LuaCppFunction bind_fun(const std::function& f) { typedef typename std::tuple::type...> Tuple; return bind_fun_specializer::type, decltype(f), Tuple>(f); } // bind a custumized function inline LuaCppFunction bind_fun(const std::function& f) { return f; } // convert to std::function then bind template LuaCppFunction bind_fun(Ret (*f)(Args...)) { return bind_fun(std::function(f)); } // a tuple_element that works with the next algorithm template struct tuple_element; template struct tuple_element<__i, std::tuple<_Head, _Tail...> > : tuple_element<__i - 1, std::tuple<_Tail...> > { }; template struct tuple_element<0, std::tuple<_Head, _Tail...> > { typedef _Head type; }; template struct tuple_element<-1,std::tuple<_Head>> { typedef void type; }; template struct tuple_element<__i,std::tuple<>> { typedef void type; }; // rebind functions already binded by std::bind that have placeholders template struct get_holded_tuple; template struct get_holded_tuple 0 && std::is_placeholder::type>::value > 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> { typedef typename std::tuple_element::type holder_type; typedef typename tuple_element::value-1, ArgsTuple>::type _arg_type; typedef typename remove_const_ref<_arg_type>::type arg_type; typedef typename get_holded_tuple::type type; }; template struct get_holded_tuple 0 && std::is_placeholder::type>::value == 0), void>::type, N, ArgsTuple, HoldersTuple, Args...> { typedef typename get_holded_tuple::type type; }; template struct get_holded_tuple { typedef typename std::tuple type; }; template LuaCppFunction bind_fun(const std::_Bind& f) { typedef typename std::tuple ArgsTuple; typedef typename std::tuple HoldersTuple; typedef typename get_holded_tuple::type Tuple; return bind_fun_specializer::type, decltype(f), Tuple>(f); } template LuaCppFunction bind_fun(const std::_Bind(Obj*, Holders...)>& f) { typedef typename std::tuple ArgsTuple; typedef typename std::tuple HoldersTuple; typedef typename get_holded_tuple::type Tuple; return bind_fun_specializer::type, decltype(f), Tuple>(f); } // custumized functions already binded by std::bind doesn't need to be bind again template LuaCppFunction bind_fun(const std::_Bind(Obj*, std::_Placeholder<1>)>& f) { return f; } inline LuaCppFunction bind_fun(const std::_Bind))(LuaState*)>& f) { return f; } // bind member function template LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...)) { auto mf = std::mem_fn(f); typedef typename std::tuple::type...> Tuple; return bind_fun_specializer::type, decltype(mf), Tuple>(mf); } template LuaCppFunction bind_mem_fun(Ret (Obj::*f)(Args...) const) { auto mf = std::mem_fn(f); typedef typename std::tuple::type...> Tuple; return bind_fun_specializer::type, decltype(mf), Tuple>(mf); } // bind custumized member function template LuaCppFunction bind_mem_fun(int (Obj::*f)(LuaState*)) { auto mf = std::mem_fn(f); return [=](LuaState* lua) { lua->insert(1); auto obj = safe_luavalue_cast(lua->popValue()); return mf(obj, lua); }; } } #endif // LUABINDER_H