Luna Wrapper

lua-users home
wiki

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. Available under the BSD 2-clause license [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;

	}


RecentChanges · preferences
edit · history
Last edited May 7, 2014 12:32 am GMT (diff)