Skip to content

Commit

Permalink
Add lua function wrapper
Browse files Browse the repository at this point in the history
Add lua function to std::function wrapper. Define flag
LUAINTF_LUA_FUNCTION_WRAPPER to 0 will disable this feature.

Add function signature guarding for safety reason.
  • Loading branch information
SteveKChiu committed Oct 24, 2014
1 parent a4565fd commit 726d067
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 12 deletions.
8 changes: 8 additions & 0 deletions LuaIntf/LuaCompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@
#define LUAINTF_UNSAFE_INT64_CHECK 0
#endif

/**
* Set LUAINTF_LUA_FUNCTION_WRAPPER to 1 if you want to automatically create std::function
* wrapper for the Lua function.
*/
#ifndef LUAINTF_LUA_FUNCTION_WRAPPER
#define LUAINTF_LUA_FUNCTION_WRAPPER 1
#endif

//---------------------------------------------------------------------------

#if !LUAINTF_BUILD_LUA_CXX
Expand Down
60 changes: 50 additions & 10 deletions LuaIntf/impl/CppFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,34 +56,74 @@ class CppFunctor

//----------------------------------------------------------------------------

template <typename FN>
struct LuaCppFunctionWrapper
{
[[noreturn]]
static const FN& get(lua_State* L, int)
{
luaL_error(L, "invalid c++ function reference");
}
};

#if LUAINTF_LUA_FUNCTION_WRAPPER

template <typename R, typename... P>
struct LuaCppFunctionWrapper <std::function<R(P...)>>
{
static std::function<R(P...)> get(lua_State* L, int index)
{
LuaRef ref(L, index);
return [ref] (P&&... arg) mutable {
return ref.call<R>(std::forward<P>(arg)...);
};
}
};

#endif

//----------------------------------------------------------------------------

/**
* Lua conversion for std::function type
*/
template <typename FN>
struct LuaCppFunction
{
using ValueType = FN;
using ReturnType = typename std::conditional<LUAINTF_LUA_FUNCTION_WRAPPER, FN, const FN&>::type;

static void push(lua_State* L, const ValueType& proc)
{
using CppProc = CppBindMethod<ValueType>;
void* userdata = lua_newuserdata(L, sizeof(ValueType));
::new (userdata) ValueType(CppProc::function(proc));
lua_pushcclosure(L, &CppProc::call, 1);
lua_pushlightuserdata(L, CppSignature<ValueType>::value());
lua_pushcclosure(L, &CppProc::call, 2);
}

static const ValueType& get(lua_State* L, int index)
static ReturnType get(lua_State* L, int index)
{
assert(lua_iscfunction(L, index));
const char* name = lua_getupvalue(L, index, 1);
assert(name && lua_isuserdata(L, -1));
const ValueType& func = *reinterpret_cast<const ValueType*>(lua_touserdata(L, -1));
assert(func);
lua_pop(L, 1);
return func;
index = lua_absindex(L, index);
if (lua_iscfunction(L, index)) {
const char* name = lua_getupvalue(L, index, 1);
if (name && lua_isuserdata(L, -1)) {
name = lua_getupvalue(L, index, 2);
if (name && lua_touserdata(L, -1) == CppSignature<ValueType>::value()) {
const ValueType& func = *reinterpret_cast<const ValueType*>(lua_touserdata(L, -2));
assert(func);
lua_pop(L, 2);
return func;
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}

return LuaCppFunctionWrapper<ValueType>::get(L, index);
}

static const ValueType& opt(lua_State* L, int index, const ValueType& def)
static ReturnType opt(lua_State* L, int index, const ValueType& def)
{
if (lua_isnoneornil(L, index)) {
return def;
Expand Down
6 changes: 6 additions & 0 deletions LuaIntf/impl/CppInvoke.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ struct CppLambdaTraits <R(FN::*)(P...) const>
using FunctionType = std::function<R(P...)>;
};

template <typename FN, typename R, typename... P>
struct CppLambdaTraits <R(FN::*)(P...)>
{
using FunctionType = std::function<R(P...)>;
};

//----------------------------------------------------------------------------

template <typename FN, typename R, typename TUPLE, size_t N, size_t... INDEX>
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ Custom type mapping

It is possible to add primitive type mapping to the `lua-intf`, all you need to do is to add template specialization to LuaValueType. You need to:

+ typedef `ValueType` type
+ define `ValueType` type
+ provide `void push(lua_State* L, const ValueType& v)`
+ provide `ValueType get(lua_State* L, int index)`
+ provide `ValueType opt(lua_State* L, int index, const ValueType& def)`
Expand All @@ -396,7 +396,7 @@ For example, to add Qt `QString` mapping to Lua string:
template <>
struct LuaValueType <QString>
{
typedef QString ValueType;
using ValueType = QString;

static void push(lua_State* L, const ValueType& str)
{
Expand Down

0 comments on commit 726d067

Please sign in to comment.