Luna Wrapper |
|
LunaWrapper is a short (53-line) wrapper to provide access to C++ classes from within Lua with relative ease. Inspired by [1] , updated for Lua 5.1. Written by nornagon. Download: [2]
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
See Also
Note
If you directly want to create the class in Lua and get a pointer back to set some values then you can add this function to the Luna class. I am new to implementing Lua to C++ so there is probably a better way for doing this and I am happy to see the approaches.// 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; }