local Stick = {}function newStick() local stick = {} setmetatable(stick, Stick) return stickendfunction isStick(stick) if getmetatable(stick) == Stick then return true else return false endendfunction Person_throwStick(person) assert( isPerson(person) ) if person.stick ~= nil then print(person.name .. " threw a stick") person.stick = nil else print(person.name .. " must hold a stick before throwing it") endendfunction Person_holdStick(person, stick) assert( isPerson(person) ) assert( isStick(stick) ) person.stick = stick print( person.name .. " is now holding a stick ")endlocal Person = {__index = {throwStick = Person_throwStick, holdStick = Person_holdStick}}function isPerson(person) if getmetatable(person) == Person then return true else return false endendfunction newPerson(name) assert( type(name) == "string" ) local person = {} setmetatable(person, Person) person.name = name return personend-- how it can be usedlocal p = newPerson("bob")local s = newStick()p:holdStick(s)p:throwStick()p:throwStick()-- results in:-- bob is now holding a stick -- bob threw a stick-- bob must hold a stick before throwing it
So, this is a nice sample using just lua. In your case, the Person table, the Stick table, the Person_ functions, etc would all be done in C. This way, the metatable would point to cfunctions instead of lua functions. Keep in mind that the p:holdStick(s) <==> p.holdStick(p, s)
define the metatables like this:
// these are the methods that MidiOut objects havestatic const luaL_reg MidiOut_meta[] = { {"__gc", MidiOut_gc}, {"noteOn", MidiOut_noteOn}, {"noteOff", MidiOut_noteOff}, {"sendMessage", MidiOut_sendMessage}, {NULL, NULL}};static int MidiOut_register(lua_State* L){ luaL_newmetatable(L, MIDIOUT); lua_pushliteral(L, "__index"); lua_newtable(L); luaL_openlib(L, 0, MidiOut_meta, 0); lua_rawset(L, -3); lua_pop(L, 1); return 1;}
this is from my midi module which had a MidiOut object with the member functions noteOn, noteOff, and sendMessage. MidiOut_noteOn, etc are all defined and coded as you would expect as a typical C/Lua wrapper function.
here are some wrapper functions for creating new objects, pushing them onto the stack, safely pulling them off of the stack, etc.
#define MIDIOUT "MidiOut"// some helper methods for accessing RtMidiOut:static RtMidiOut* toMidiOut(lua_State *L, int index){ RtMidiOut **midiout = (RtMidiOut**)lua_touserdata(L, index); if(midiout == NULL) luaL_typerror(L, index, MIDIOUT); return *midiout;}static RtMidiOut* checkMidiOut(lua_State* L, int index){ RtMidiOut** midiout; RtMidiOut* ret; luaL_checktype(L, index, LUA_TUSERDATA); midiout = (RtMidiOut**)luaL_checkudata(L, index, MIDIOUT); if(midiout == NULL) luaL_typerror(L, index, MIDIOUT); ret = *midiout; if(!ret) luaL_error(L, "null RtMidiOut*"); return ret;}static RtMidiOut** pushMidiOut(lua_State* L, RtMidiOut* mo){ RtMidiOut** midiout = (RtMidiOut**)lua_newuserdata(L, sizeof(RtMidiOut*)); *midiout = mo; luaL_getmetatable(L, MIDIOUT); lua_setmetatable(L, -2); return midiout;}static int MidiOut_noteOn(lua_State *L){ RtMidiOut* midiout = checkMidiOut(L, 1); midiout->noteOn( ... ); return 0;}
Let me know if you have any more questions. I only recently figured all of this stuff out, so it will definitely help me get a clearer understanding of it all.