613 lines
23 KiB
C++
613 lines
23 KiB
C++
/**
|
|
* Copyright (c) 2010-2013 Alexander Ames
|
|
* Alexander.Ames@gmail.com
|
|
* See Copyright Notice at the end of this file
|
|
*/
|
|
|
|
/** API Summary:
|
|
*
|
|
* This is a set of utility functions that add to the functionalit of
|
|
* LuaWrapper. Over time I found myself repeating a few patterns, such as
|
|
* writing many trvial getter and setter functions, and wanting pass ownership
|
|
* of one object to another and have the Lua script properly handle that case.
|
|
*
|
|
* This file contains the additional functions that I've added but that do
|
|
* not really belong in the core API.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <luaWrapper/luaWrapper.hpp>
|
|
|
|
#include <type_traits>
|
|
|
|
#ifndef LUAW_STD
|
|
#define LUAW_STD std
|
|
#endif
|
|
|
|
namespace luaWrapper {
|
|
namespace utils {
|
|
/**
|
|
* @brief This template removes reference and const qualifier from the type
|
|
*/
|
|
template <typename LUAW_TYPE> struct remove_cr {
|
|
typedef typename std::remove_const<typename std::remove_reference<LUAW_TYPE>::type>::type type;
|
|
};
|
|
|
|
|
|
/**
|
|
* This is slightly different than the previous three functions in that you
|
|
* shouldn't need to write your own version of it, since it uses check
|
|
* automatically.
|
|
*/
|
|
template<typename U> U opt(lua_State* _luaState, int _index, const U& _fallback = U()) {
|
|
if (lua_isnil(_luaState, _index)) {
|
|
return _fallback;
|
|
} else {
|
|
return luaWrapper::utils::check<U>(_luaState, _index);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* These are just some functions I've always felt should exist
|
|
*/
|
|
template <typename U> inline U getfield(lua_State* _luaState, int _index, const char* _field) {
|
|
static_assert(!LUAW_STD::is_same<U, const char*>::value,
|
|
"luaWrapper::utils::getfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
|
lua_getfield(_luaState, _index, _field);
|
|
U val = luaWrapper::utils::to<U>(_luaState, -1);
|
|
lua_pop(_luaState, 1);
|
|
return val;
|
|
}
|
|
|
|
template <typename U> inline U checkfield(lua_State* _luaState, int _index, const char* _field) {
|
|
static_assert(!LUAW_STD::is_same<U, const char*>::value,
|
|
"luaWrapper::utils::checkfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
|
lua_getfield(_luaState, _index, _field);
|
|
U val = luaWrapper::utils::check<U>(_luaState, -1);
|
|
lua_pop(_luaState, 1);
|
|
return val;
|
|
}
|
|
|
|
template <typename U> inline U optfield(lua_State* _luaState, int _index, const char* _field, const U& _fallback = U()) {
|
|
static_assert(!LUAW_STD::is_same<U, const char*>::value,
|
|
"luaWrapper::utils::getfield is not safe to use on const char*'s. (The string will be popped from the stack.)");
|
|
lua_getfield(_luaState, _index, _field);
|
|
U val = luaWrapper::utils::opt<U>(_luaState, -1, _fallback);
|
|
lua_pop(_luaState, 1);
|
|
return val;
|
|
}
|
|
|
|
template <typename U> inline void setfield(lua_State* _luaState, int _index, const char* _field, U _val) {
|
|
luaWrapper::utils::push<U>(_luaState, _val);
|
|
lua_setfield(_luaState, luaWrapper::correctindex(_luaState, _index, 1), _field);
|
|
}
|
|
|
|
/** A set of trivial getter and setter templates. These templates are designed
|
|
* to call trivial getters or setters.
|
|
*
|
|
* There are four forms:
|
|
* 1. Getting or setting a public member variable that is of a primitive type
|
|
* 2. Getting or setting a public member variable that is a pointer to an
|
|
* object
|
|
* 3. Getting or setting a private member variable that is of a primitive type
|
|
* through a getter or setter
|
|
* 3. Getting or setting a private member variable that is is a pointer to an
|
|
* object through a getter or setter
|
|
*
|
|
* The interface to all of them is the same however. In addition to plain
|
|
* getter and setter functions, there is a getSet which does both - if an
|
|
* argument is supplied it attempts to set the value, and in either case it
|
|
* returns the value. In your lua table declaration in C++ rather than write
|
|
* individiual wrappers for each getter and setter you may do the following:
|
|
*
|
|
* static luaL_reg Foo_metatable[] =
|
|
* {
|
|
* { "GetBar", luaWrapper::utils::get<Foo, bool, &Widget::GetBar> },
|
|
* { "SetBar", luaWrapper::utils::set<Foo, bool, &Widget::SetBar> },
|
|
* { "Bar", luaWrapper::utils::getSet<Foo, bool, &Widget::GetBar, &Widget::SetBar> },
|
|
* { NULL, NULL }
|
|
* }
|
|
*
|
|
* Getters and setters must have one of the following signatures:
|
|
* void LUAW_TYPE::Setter(U _value);
|
|
* void LUAW_TYPE::Setter(U* _value);
|
|
* void LUAW_TYPE::Setter(const U& _value);
|
|
* U Getter() const;
|
|
* U* Getter() const;
|
|
*
|
|
* In this example, the variable Foo::bar is private and so it is accessed
|
|
* through getter and setter functions. If Foo::bar were public, it could be
|
|
* accessed directly, like so:
|
|
*
|
|
* static luaL_reg Foo_metatable[] =
|
|
* {
|
|
* { "GetBar", luaWrapper::utils::get<Foo, bool, &Widget::bar> },
|
|
* { "SetBar", luaWrapper::utils::set<Foo, bool, &Widget::bar> },
|
|
* { "Bar", luaWrapper::utils::getSet<Foo, bool, &Widget::bar> },
|
|
* }
|
|
*
|
|
* In a Lua script, you can now use foo:GetBar(), foo:SetBar() and foo:Bar()
|
|
*/
|
|
|
|
template <typename LUAW_TYPE, typename U, U LUAW_TYPE::*Member> int get(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
luaWrapper::utils::push<U>(_luaState, obj.get()->*Member);
|
|
return 1;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* LUAW_TYPE::*Member> int get(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
luaWrapper::push<U>(_luaState, obj.get()->*Member);
|
|
return 1;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U (LUAW_TYPE::*Getter)() const> int get(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
luaWrapper::utils::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, const U& (LUAW_TYPE::*Getter)() const> int get(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
luaWrapper::utils::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* (LUAW_TYPE::*Getter)() const> int get(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
luaWrapper::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U LUAW_TYPE::*Member> int set(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
obj.get()->*Member = luaWrapper::utils::check<U>(_luaState, 2);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* LUAW_TYPE::*Member> int set(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
obj.get()->*Member = member.get();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, const U* LUAW_TYPE::*Member> int set(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
obj.get()->*Member = member.get();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, const U* LUAW_TYPE::*Member> int setAndRelease(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
obj.get()->*Member = member.get();
|
|
if (member) {
|
|
luaWrapper::release<U>(_luaState, member);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, void (LUAW_TYPE::*Setter)(U)> int set(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
(obj.get()->*Setter)(luaWrapper::utils::check<U>(_luaState, 2));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, void (LUAW_TYPE::*Setter)(const U&)> int set(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
(obj.get()->*Setter)(luaWrapper::utils::check<U>(_luaState, 2));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, void (LUAW_TYPE::*Setter)(U*)> int set(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
(obj.get()->*Setter)(member.get());
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, void (LUAW_TYPE::*Setter)(U*)> int setAndRelease(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if (obj != null) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
(obj.get()->*Setter)(member);
|
|
if (member) {
|
|
luaWrapper::release<U>(_luaState, member);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U LUAW_TYPE::*Member> int getSet(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
obj.get()->*Member = luaWrapper::utils::check<U>(_luaState, 2);
|
|
return 0;
|
|
} else {
|
|
luaWrapper::utils::push<U>(_luaState, obj.get()->*Member);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* LUAW_TYPE::*Member> int getSet(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
obj.get()->*Member = member.get();
|
|
return 0;
|
|
} else {
|
|
luaWrapper::push<U>(_luaState, obj.get()->*Member);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* LUAW_TYPE::*Member> int getSetAndRelease(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
obj.get()->*Member = member.get();
|
|
if (member)
|
|
luaWrapper::release<U>(_luaState, member);
|
|
return 0;
|
|
} else {
|
|
luaWrapper::push<U>(_luaState, obj.get()->*Member);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U (LUAW_TYPE::*Getter)() const, void (LUAW_TYPE::*Setter)(U)> int getSet(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
(obj.get()->*Setter)(luaWrapper::utils::check<U>(_luaState, 2));
|
|
return 0;
|
|
} else {
|
|
luaWrapper::utils::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U (LUAW_TYPE::*Getter)() const, void (LUAW_TYPE::*Setter)(const U&)> int getSet(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
(obj.get()->*Setter)(luaWrapper::utils::check<U>(_luaState, 2));
|
|
return 0;
|
|
} else {
|
|
luaWrapper::utils::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, const U& (LUAW_TYPE::*Getter)() const, void (LUAW_TYPE::*Setter)(const U&)> int getSet(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
(obj.get()->*Setter)(luaWrapper::utils::check<U>(_luaState, 2));
|
|
return 0;
|
|
} else {
|
|
luaWrapper::utils::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* (LUAW_TYPE::*Getter)() const, void (LUAW_TYPE::*Setter)(U*)> int getSet(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
(obj.get()->*Setter)(member.get());
|
|
return 0;
|
|
} else {
|
|
luaWrapper::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
template <typename LUAW_TYPE, typename U, U* (LUAW_TYPE::*Getter)() const, void (LUAW_TYPE::*Setter)(U*)> int getSetAndRelease(lua_State* _luaState) {
|
|
ememory::SharedPtr<LUAW_TYPE> obj = luaWrapper::check<LUAW_TYPE>(_luaState, 1);
|
|
if ( obj != null
|
|
&& lua_gettop(_luaState) >= 2) {
|
|
ememory::SharedPtr<U> member = luaWrapper::opt<U>(_luaState, 2);
|
|
(obj.get()->*Setter)(member);
|
|
if (member)
|
|
luaWrapper::release<U>(_luaState, member);
|
|
return 0;
|
|
} else {
|
|
luaWrapper::push<U>(_luaState, (obj.get()->*Getter)());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* luaWrapper::utils::func is a special macro that expands into a simple function wrapper.
|
|
* Unlike the getter setters above, you merely need to name the function you
|
|
* would like to wrap.
|
|
*
|
|
* For example,
|
|
*
|
|
* struct Foo
|
|
* {
|
|
* int doSomething(int, const char*);
|
|
* };
|
|
*
|
|
* static luaL_reg Foo_metatable[] =
|
|
* {
|
|
* { "doSomething", luaWrapper::utils::func(&Foo::doSomething) },
|
|
* { NULL, NULL }
|
|
* }
|
|
*
|
|
* void RegisterFoo(lua_State* L)
|
|
* {
|
|
* luaWrapper::registerElement<Foo>(L, "Foo", NULL, Foo_metatable);
|
|
* }
|
|
*
|
|
* This macro will expand based on the function signature of Foo::DoSomething
|
|
* In this example, it would expand into the following wrapper:
|
|
*
|
|
* luaWrapper::utils::push(luaWrapper::check<T>(L, 1)->doSomething(luaWrapper::utils::check<int>(L, 2), luaWrapper::utils::check<const char*>(L, 3)));
|
|
* return 1;
|
|
*
|
|
* In this example there is only one member function called DoSomething. In some
|
|
* cases there may be multiple overrides for a function. For those cases, an
|
|
* additional macro has been provided, luaWrapper::utils::funcsig, which takes the entire
|
|
* function signature. The arguments to the macro reflect the order they would
|
|
* appear in the function signature: return type, type name, function name, and
|
|
* finally a list of all the argument types. For example:
|
|
*
|
|
* struct Foo
|
|
* {
|
|
* int DoSomething (const char*);
|
|
* int DoSomething (const char*, int);
|
|
* };
|
|
*
|
|
* const struct luaL_Reg Foo_metatable[] =
|
|
* {
|
|
* {"DoSomething1", luaWrapper::utils::funcsig(int, Foo, DoSomething, const char*)) },
|
|
* {"DoSomething1", luaWrapper::utils::funcsig(int, Foo, DoSomething, const char*, int)) },
|
|
* { NULL, NULL }
|
|
* };
|
|
*
|
|
* There`s also support for static and freestanding functions. Macros luaWrapper::utils::staticfunc
|
|
* and luaWrapper::utils::staticfuncsig work equally to luaWrapper::utils::func and luaWrapper::utils::funcsig, except for that
|
|
* you need to provide a separate metatable for static functions.
|
|
* For example,
|
|
*
|
|
* struct Foo
|
|
* {
|
|
* int DoSomething(int, const char*);
|
|
* static void DoSomethingElse(int a, int b, float c);
|
|
* };
|
|
*
|
|
* static luaL_reg Foo_metatable[] =
|
|
* {
|
|
* { "DoSomething", luaWrapper::utils::func(&Foo::DoSomething) },
|
|
* { NULL, NULL }
|
|
* };
|
|
*
|
|
* static luaL_reg Foo_metatable_static[] =
|
|
* {
|
|
* { "DoSomethingElse", luaWrapper::utils::staticfunc(&Foo::DoSomethingElse) },
|
|
* { NULL, NULL }
|
|
* };
|
|
*
|
|
* void RegisterFoo(lua_State* L)
|
|
* {
|
|
* luaWrapper::registerElement<Foo>(L, "Foo", Foo_metatable_static, Foo_metatable);
|
|
* }
|
|
*
|
|
* After that you will be able to use Foo class from Lua like this:
|
|
* local foo = Foo.new()
|
|
* foo:DoSomething(42, 'The Ultimate Question of Life, the Universe, and Everything.') -- member function call
|
|
* Foo:DoSomethingElse(30, 12, 3.1459) -- Static function call
|
|
*
|
|
* These macros and it's underlying templates are somewhat experimental and some
|
|
* refinements are probably needed. There are cases where it does not
|
|
* currently work and I expect some changes can be made to refine its behavior.
|
|
*/
|
|
|
|
#define luaWrapperUtils_func(memberfunc) &luaWrapper::utils::MemberFuncWrapper<decltype(memberfunc),memberfunc>::call
|
|
#define luaWrapperUtils_funcsig(returntype, type, funcname, ...) luaWrapperUtilsfunc(static_cast<returntype (type::*)(__VA_ARGS__)>(&type::funcname))
|
|
|
|
#define luaWrapperUtils_staticfunc(func) &luaWrapper::utils::StaticFuncWrapper<decltype(func),func>::call
|
|
#define luaWrapperUtils_staticfuncsig(returntype, type, funcname, ...) luaWrapperUtilsstaticfunc(static_cast<returntype (*)(__VA_ARGS__)>(&type::funcname))
|
|
|
|
template<int... ints> struct IntPack { };
|
|
template<int start, int count, int... tail> struct MakeIntRangeType {
|
|
typedef typename MakeIntRangeType<start, count-1, start+count-1, tail...>::type type;
|
|
};
|
|
template<int start, int... tail> struct MakeIntRangeType<start, 0, tail...> {
|
|
typedef IntPack<tail...> type;
|
|
};
|
|
template<int start, int count> inline typename MakeIntRangeType<start, count>::type makeIntRange() {
|
|
return typename MakeIntRangeType<start, count>::type();
|
|
}
|
|
|
|
/**
|
|
* Member function wrapper
|
|
*/
|
|
template<class LUAW_MEMORY_FUNCTION_POINTER_TYPE, LUAW_MEMORY_FUNCTION_POINTER_TYPE MemberFunc>
|
|
struct MemberFuncWrapper;
|
|
|
|
template<class LUAW_TYPE, class ReturnType, class... Args, ReturnType(LUAW_TYPE::*MemberFunc)(Args...)>
|
|
struct MemberFuncWrapper<ReturnType (LUAW_TYPE::*)(Args...), MemberFunc> {
|
|
public:
|
|
static int call(lua_State* _luaState) {
|
|
return callImpl(_luaState, makeIntRange<2,sizeof...(Args)>());
|
|
}
|
|
private:
|
|
template<int... indices> static int callImpl(lua_State* _luaState, IntPack<indices...>) {
|
|
luaWrapper::utils::push<ReturnType>(_luaState, ((*luaWrapper::check<LUAW_TYPE>(_luaState, 1)).*MemberFunc)(luaWrapper::utils::check<typename luaWrapper::utils::remove_cr<Args>::type>(_luaState, indices)...));
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
template<class LUAW_TYPE, class... Args, void(LUAW_TYPE::*MemberFunc)(Args...)>
|
|
struct MemberFuncWrapper<void(LUAW_TYPE::*)(Args...), MemberFunc> {
|
|
public:
|
|
static int call(lua_State* _luaState) {
|
|
return callImpl(_luaState, luaWrapper::utils::makeIntRange<2, sizeof...(Args)>());
|
|
}
|
|
private:
|
|
template<int... indices>
|
|
static int callImpl(lua_State* _luaState, IntPack<indices...>) {
|
|
((*luaWrapper::check<LUAW_TYPE>(_luaState, 1)).*MemberFunc)(luaWrapper::utils::check<typename luaWrapper::utils::remove_cr<Args>::type>(_luaState, indices)...);
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* static function wrapper
|
|
*/
|
|
|
|
template<class LUAW_FUNCTION_POINTER_TYPE, LUAW_FUNCTION_POINTER_TYPE LUAW_FUNCTION>
|
|
struct StaticFuncWrapper;
|
|
|
|
template<class ReturnType, class... Args, ReturnType(*LUAW_FUNCTION)(Args...)>
|
|
struct StaticFuncWrapper<ReturnType(*)(Args...), LUAW_FUNCTION> {
|
|
public:
|
|
static int call(lua_State* _luaState) {
|
|
return callImpl(_luaState, luaWrapper::utils::makeIntRange<2,sizeof...(Args)>());
|
|
}
|
|
private:
|
|
template<int... indices> static int callImpl(lua_State* _luaState, IntPack<indices...>) {
|
|
luaWrapper::utils::push<ReturnType>(_luaState, (*LUAW_FUNCTION)(luaWrapper::utils::check<typename luaWrapper::utils::remove_cr<Args>::type>(_luaState, indices)...));
|
|
return 1;
|
|
}
|
|
};
|
|
|
|
template<class... Args, void(*LUAW_FUNCTION)(Args...)>
|
|
struct StaticFuncWrapper<void(*)(Args...), LUAW_FUNCTION> {
|
|
public:
|
|
static int call(lua_State* _luaState) {
|
|
return callImpl(_luaState, luaWrapper::utils::makeIntRange<2, sizeof...(Args)>());
|
|
}
|
|
private:
|
|
template<int... indices>
|
|
static int callImpl(lua_State* _luaState, luaWrapper::utils::IntPack<indices...>) {
|
|
(*LUAW_FUNCTION)(luaWrapper::utils::check<typename luaWrapper::utils::remove_cr<Args>::type>(_luaState, indices)...);
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calls the copy constructor for an object of type T.
|
|
* Arguments may be passed in, in case they're needed for the postconstructor
|
|
*
|
|
* e.g.
|
|
*
|
|
* C++:
|
|
* luaL_reg Foo_Metatable[] =
|
|
* {
|
|
* { "clone", luaWrapper::utils::clone<Foo> },
|
|
* { NULL, NULL }
|
|
* };
|
|
*
|
|
* Lua:
|
|
* foo = Foo.new()
|
|
* foo2 = foo:clone()
|
|
*/
|
|
template <typename LUAW_TYPE> int clone(lua_State* _luaState) {
|
|
LUAW_TYPE* obj = new LUAW_TYPE(*luaWrapper::check<LUAW_TYPE>(_luaState, 1));
|
|
lua_remove(_luaState, 1); // ...
|
|
int numargs = lua_gettop(_luaState);
|
|
luaWrapper::push<LUAW_TYPE>(_luaState, obj); // ... clone
|
|
luaWrapper::hold<LUAW_TYPE>(_luaState, obj);
|
|
luaWrapper::postconstructor<LUAW_TYPE>(_luaState, numargs);
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* luaWrapper::utils::build is intended to be used to initialize many values by passing in a
|
|
* table. They keys of the table are used as function names, and values are
|
|
* used as arguments to the function. This is intended to be used on functions
|
|
* that are simple setters.
|
|
*
|
|
* For example, if luaWrapper::utils::build is set as the post constructor, you can
|
|
* initialize an object as so:
|
|
*
|
|
* f = Foo.new
|
|
* {
|
|
* X = 10;
|
|
* Y = 20;
|
|
* }
|
|
*
|
|
* After the object is constructed, luaWrapper::utils::build will do the equivalent of
|
|
* calling f:X(10) and f:Y(20).
|
|
*/
|
|
template <typename LUAW_TYPE> int build(lua_State* _luaState) {
|
|
// obj {}
|
|
lua_insert(_luaState, -2); // {} obj
|
|
if (lua_type(_luaState, 1) == LUA_TTABLE) {
|
|
for (lua_pushnil(_luaState); lua_next(_luaState, 1); lua_pop(_luaState, 1)) {
|
|
// {} obj k v
|
|
lua_pushvalue(_luaState, -2); // {} obj k v k
|
|
lua_gettable(_luaState, -4); // {} obj k v ud[k]
|
|
lua_pushvalue(_luaState, -4); // {} obj k v ud[k] ud
|
|
lua_pushvalue(_luaState, -3); // {} obj k v ud[k] ud v
|
|
lua_call(_luaState, 2, 0); // {} obj k v
|
|
}
|
|
// {} ud
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Takes the object of type T at the top of the stack and stores it in on a
|
|
* table with the name storagetable, on the table at the specified _index.
|
|
*
|
|
* You may manually call luaWrapper::hold and luaWrapper::release to handle pointer
|
|
* ownership, but it is often easier to simply store a Lua userdata on a table
|
|
* that is owned by its parent. This ensures that your object will not be
|
|
* prematurely freed, and that it can only be destoryed after its parent.
|
|
*
|
|
* e.g.
|
|
*
|
|
* Foo* parent = luaWrapper::check<Foo>(_luaState, 1);
|
|
* Bar* child = luaWrapper::check<Bar>(_luaState, 2);
|
|
* if (parent && child)
|
|
* {
|
|
* luaWrapper::utils::store<Bar>(_luaState, 1, "Children");
|
|
* parent->AddChild(child);
|
|
* }
|
|
*/
|
|
template <typename LUAW_TYPE> void store(lua_State* _luaState, int _index, const char* _storagetable, const char* _key = NULL) {
|
|
// ... store ... obj store.storagetable
|
|
lua_getfield(_luaState, _index, _storagetable);
|
|
if (_key) {
|
|
// ... store ... obj store.storagetable key
|
|
lua_pushstring(_luaState, _key);
|
|
} else {
|
|
// ... store ... obj store.storagetable key
|
|
LuaWrapper<LUAW_TYPE>::identifier(_luaState, luaWrapper::to<LUAW_TYPE>(_luaState, -2));
|
|
}
|
|
// ... store ... obj store.storagetable key obj
|
|
lua_pushvalue(_luaState, -3);
|
|
// ... store ... obj store.storagetable
|
|
lua_settable(_luaState, -3);
|
|
// ... store ... obj
|
|
lua_pop(_luaState, 1);
|
|
}
|
|
}
|
|
}
|