Luna Wrapper |
|
LunaFour provides additional features such as properties (requires modification to Lua) and functions for retrieving and returning classes from C++.
template<class T> class Luna {
public:
static void Register(lua_State *L) {
lua_pushcfunction(L, &Luna<T>::constructor);
lua_setglobal(L, T::className);
luaL_newmetatable(L, T::className);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &Luna<T>::gc_obj);
lua_settable(L, -3);
}
static int constructor(lua_State *L) {
T* obj = new T(L);
lua_newtable(L);
lua_pushnumber(L, 0);
T** a = (T**)lua_newuserdata(L, sizeof(T*));
*a = obj;
luaL_getmetatable(L, T::className);
lua_setmetatable(L, -2);
lua_settable(L, -3); // table[0] = obj;
for (int i = 0; T::Register[i].name; i++) {
lua_pushstring(L, T::Register[i].name);
lua_pushnumber(L, i);
lua_pushcclosure(L, &Luna<T>::thunk, 1);
lua_settable(L, -3);
}
return 1;
}
static int thunk(lua_State *L) {
int i = (int)lua_tonumber(L, lua_upvalueindex(1));
lua_pushnumber(L, 0);
lua_gettable(L, 1);
T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
lua_remove(L, -1);
return ((*obj)->*(T::Register[i].mfunc))(L);
}
static int gc_obj(lua_State *L) {
T** obj = static_cast<T**>(luaL_checkudata(L, -1, T::className));
delete (*obj);
return 0;
}
struct RegType {
const char *name;
int(T::*mfunc)(lua_State*);
};
};
class Foo {
public:
Foo(lua_State *L) {
printf("in constructor\n");
}
int foo(lua_State *L) {
printf("in foo\n");
}
~Foo() {
printf("in destructor\n");
}
static const char className[];
static const Luna<Foo>::RegType Register[];
};
const char Foo::className[] = "Foo";
const Luna<Foo>::RegType Foo::Register[] = {
{ "foo", &Foo::foo },
{ 0 }
};
Then somewhere during initialization:
Luna<Foo>::Register(L);
From lua:
local foo = Foo()
foo:foo()
Later:
lua_close(L);
Results:
in constructor in foo in destructor
// Directly add the new class
static T* RegisterTable(lua_State *L)
{
luaL_newmetatable(L, T::className);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &Luna<T>::gc_obj);
lua_settable(L, -3);
T* obj = new T(L);
lua_newtable(L);
lua_pushnumber(L, 0);
T** a = (T**)lua_newuserdata(L, sizeof(T*));
*a = obj;
luaL_getmetatable(L, T::className);
lua_setmetatable(L, -2);
lua_settable(L, -3); // table[0] = obj;
for (int i = 0; T::Register[i].name; i++)
{
lua_pushstring(L, T::Register[i].name);
lua_pushnumber(L, i);
lua_pushcclosure(L, &Luna<T>::thunk, 1);
lua_settable(L, -3);
}
lua_setglobal(L, T::className);
return obj;
}