Luna Four Code

lua-users home
wiki


template < class T > class Luna {

    typedef struct {

	T              *pT;

    } userdataType;

    

  public:



    enum {

	NUMBER,

	STRING

    };



    struct PropertyType {

	const char     *name;

	int             (T::*getter) (lua_State *);

	int             (T::*setter) (lua_State *);

    };



    struct FunctionType {

	const char     *name;

	int             (T::*function) (lua_State *);

    };



/*

  @ check

  Arguments:

    * L - Lua State

    * narg - Position to check



  Description:

    Retrieves a wrapped class from the arguments passed to the function, specified by narg (position).

    This function will raise an exception if the argument is not of the correct type.

*/

    static T       *check(lua_State * L, int narg) {

	// Check to see whether we are a table

	    if (lua_istable(L,narg+1))

	    {

		    lua_gettablevalue(L,narg+1,0);

		    userdataType   *ud =

				    static_cast <userdataType * >(luaL_checkudata(L, -1, T::className));

		    if (!ud)

			    luaL_typerror(L, narg+1, T::className);

		    lua_pop(L,1);

		    return ud->pT;		// pointer to T object

	    }

	    else

	    {

		    luaL_typerror(L, narg+1, T::className);

	    } 

    }



/*

  @ lightcheck

  Arguments:

    * L - Lua State

    * narg - Position to check



  Description:

    Retrieves a wrapped class from the arguments passed to the function, specified by narg (position).

    This function will return NULL if the argument is not of the correct type.  Useful for supporting

    multiple types of arguments passed to the function

*/ 

	static T       *lightcheck(lua_State * L, int narg) {

	// Check to see whether we are a table

	    if (lua_istable(L,narg+1))

	    {

		    lua_gettablevalue(L,narg+1,0);

		    userdataType   *ud =

				    static_cast <userdataType * >(luaL_testudata(L, -1, T::className));

		    if (!ud)

			    return NULL; // lightcheck returns NULL if not found.

		    lua_pop(L,1);

		    return ud->pT;		// pointer to T object

	    }

	    else

	    {

		    return NULL;

	    } 

    }



/*

  @ Register

  Arguments:

    * L - Lua State

    * namespac - Namespace to load into



  Description:

    Registers your class with Lua.  Leave namespac "" if you want to load it into the global space.

*/

    // REGISTER CLASS AS A GLOBAL TABLE 

    static void     Register(lua_State * L, const char *namespac) {



	if (strcmp(namespac, "") != 0) {

	    lua_getglobal(L, namespac);

	    lua_pushcfunction(L, &Luna < T >::constructor);

	    lua_setfield(L, -2, T::className);

	    lua_pop(L, 1);

	} else {

	    lua_pushcfunction(L, &Luna < T >::constructor);

	    lua_setglobal(L, T::className);

	}



	luaL_newmetatable(L, T::className);

	int             metatable = lua_gettop(L);



	lua_pushstring(L, "__gc");

	lua_pushcfunction(L, &Luna < T >::gc_obj);

	lua_settable(L, metatable);



	lua_pushstring(L, "__index");

	lua_pushcfunction(L, &Luna < T >::property_getter);

	lua_settable(L, metatable);



	lua_pushstring(L, "__newindex");

	lua_pushcfunction(L, &Luna < T >::property_setter);

	lua_settable(L, metatable);



    }



/*

  @ constructor (internal)

  Arguments:

    * L - Lua State

*/

    static int      constructor(lua_State * L) {



	lua_newtable(L);



	int             newtable = lua_gettop(L);



	lua_pushnumber(L, 0);



	T             **a = (T **) lua_newuserdata(L, sizeof(T *));

	T              *obj = new T(L, true);

	*a = obj;



	int             userdata = lua_gettop(L);



	luaL_getmetatable(L, T::className);



	lua_setmetatable(L, userdata);



	lua_settable(L, newtable);



	luaL_getmetatable(L, T::className);

	lua_setmetatable(L, newtable);



	luaL_getmetatable(L, T::className);



	for (int i = 0; T::Properties[i].name; i++) {

	    lua_pushstring(L, T::Properties[i].name);

	    lua_pushnumber(L, i);

	    lua_settable(L, -3);

	}



	lua_pop(L, 1);



	for (int i = 0; T::Functions[i].name; i++) {

	    lua_pushstring(L, T::Functions[i].name);

	    lua_pushnumber(L, i);

	    lua_pushcclosure(L, &Luna < T >::function_dispatch, 1);

	    lua_settable(L, newtable);

	}



	return 1;

    }



/*

  @ createNew

  Arguments:

    * L - Lua State



  Description:

    Loads an instance of the class into the Lua stack, and provides you a pointer so you can modify it.

*/

    static T       *createNew(lua_State * L) {



	lua_newtable(L);



	int             newtable = lua_gettop(L);



	lua_pushnumber(L, 0);



	T             **a = (T **) lua_newuserdata(L, sizeof(T *));

	T              *obj = new T(L, false);

	obj->isExisting = false;

	*a = obj;



	int             userdata = lua_gettop(L);



	luaL_getmetatable(L, T::className);



	lua_setmetatable(L, userdata);



	lua_settable(L, newtable);



	luaL_getmetatable(L, T::className);

	lua_setmetatable(L, newtable);



	luaL_getmetatable(L, T::className);



	for (int i = 0; T::Properties[i].name; i++) {

	    // ADD NAME KEY 

	    lua_pushstring(L, T::Properties[i].name);

	    lua_pushnumber(L, i);

	    lua_settable(L, -3);

	}



	lua_pop(L, 1);



	for (int i = 0; T::Functions[i].name; i++) {

	    lua_pushstring(L, T::Functions[i].name);

	    lua_pushnumber(L, i);

	    lua_pushcclosure(L, &Luna < T >::function_dispatch, 1);

	    lua_settable(L, newtable);

	}



	return obj;

    }



/*

  @ createFromExisting

  Arguments:

    * L - Lua State

    * existingobj - Existing instance of object



  Description:

    Loads an instance of the class into the Lua stack, instead using an existing object rather than creating a new one.

    Returns the existing object.

*/

    static T       *createFromExisting(lua_State * L, T * existingobj) {



	lua_newtable(L);



	int             newtable = lua_gettop(L);



	lua_pushnumber(L, 0);



	T             **a = (T **) lua_newuserdata(L, sizeof(T *));

	T              *obj = existingobj;

	obj->isExisting = true;

	*a = obj;



	int             userdata = lua_gettop(L);





	luaL_getmetatable(L, T::className);



	lua_setmetatable(L, userdata);



	lua_settable(L, newtable);



	luaL_getmetatable(L, T::className);

	lua_setmetatable(L, newtable);



	luaL_getmetatable(L, T::className);



	for (int i = 0; T::Properties[i].name; i++) {

	    lua_pushstring(L, T::Properties[i].name);

	    lua_pushnumber(L, i);

	    lua_settable(L, -3);

	}



	lua_pop(L, 1);



	for (int i = 0; T::Functions[i].name; i++) {

	    lua_pushstring(L, T::Functions[i].name);

	    lua_pushnumber(L, i);

	    lua_pushcclosure(L, &Luna < T >::function_dispatch, 1);

	    lua_settable(L, newtable);

	}



	return obj;

    }



/*

  @ property_getter (internal)

  Arguments:

    * L - Lua State

*/

    static int      property_getter(lua_State * L) {



	lua_pushvalue(L, 2);



	lua_getmetatable(L, 1);



	lua_pushvalue(L, 2);

	lua_rawget(L, -2);



	if (lua_isnumber(L, -1)) {



	    int             _index = lua_tonumber(L, -1);



	    lua_pushnumber(L, 0);

	    lua_rawget(L, 1);



	    T             **obj =

		static_cast < T ** >(lua_touserdata(L, -1));



	    lua_pushvalue(L, 3);



	    const PropertyType *_properties = (*obj)->T::Properties;



		int result = ((*obj)->*(T::Properties[_index].getter)) (L);



	    return result;



	}

	// PUSH NIL 

	lua_pushnil(L);



	return 1;



    }



/*

  @ property_setter (internal)

  Arguments:

    * L - Lua State

*/

    static int      property_setter(lua_State * L) {



	lua_getmetatable(L, 1);



	lua_pushvalue(L, 2);

	lua_rawget(L, -2);



	if (lua_isnil(L, -1)) {



	    lua_pop(L, 2);



	    lua_rawset(L, 1);



	    return 0;

	} else {



	    int             _index = lua_tonumber(L, -1);



	    lua_pushnumber(L, 0);

	    lua_rawget(L, 1);



	    T             **obj =

		static_cast < T ** >(lua_touserdata(L, -1));



	    lua_pushvalue(L, 3);



	    const PropertyType *_properties = (*obj)->T::Properties;



	    return ((*obj)->*(T::Properties[_index].setter)) (L);



	}



    }



/*

  @ function_dispatch (internal)

  Arguments:

    * L - Lua State

*/

    static int      function_dispatch(lua_State * L) {



	int             i = (int) lua_tonumber(L, lua_upvalueindex(1));



	lua_pushnumber(L, 0);

	lua_rawget(L, 1);



	T             **obj = static_cast < T ** >(lua_touserdata(L, -1));



	lua_pop(L, 1);



	return ((*obj)->*(T::Functions[i].function)) (L);

    }



/*

  @ gc_obj (internal)

  Arguments:

    * L - Lua State

*/

    static int      gc_obj(lua_State * L) {



	T             **obj =

	    static_cast < T ** >(luaL_checkudata(L, -1, T::className));



	if (!(*obj)->isExisting && !(*obj)->isPrecious)

	{

		cout << "Cleaning up a " << T::className << "." << endl;

		delete(*obj);

	}



	return 0;

    }



};


RecentChanges · preferences
edit · history
Last edited December 21, 2012 10:52 pm GMT (diff)