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; }