I'm attempting to write an asynchronous library that uses callbacks.
From script, the callbacks look like
foo = Async.New()
function asyncCallback( async, data )
print( "optional data is "..data )
result, e = async:EndCall()
end
foo:BeginCall(asyncCallback, "optional test data")
Internally, I'll have a global table which will hold
lightuserdata:table. The lightuserdata is a pointer to an internal
structure and it's value is a table which contains the Async object,
the callback function and the data argument. When the C++ function
calls back, it looks up the lightuserdata in the table and calls the
function, passing the object and the data as parameters.
Ignoring some big holes ( like I'll need to protect the lua_State
when the callback comes back on another thread ) is there anything
fundamentally wrong with the concept, or the following code?
const char* AsyncClass = "Async";
const char* AsyncInfoTable = "AsyncInfoTable";
const char* AsyncField = "Async";
const char* FunctionField = "Function";
const char* DataField = "Data";
class LuaAsync;
struct AsyncInfo
{
lua_State* L;
};
class LuaAsync
{
protected:
void CallAsync(AsyncInfo* info)
{
// this would actually do something here and get called back
lua_getglobal(info->L, AsyncInfoTable);
lua_pushlightuserdata(info->L,info);
lua_gettable(info->L,-2);
// remove our userdata entry from the table
lua_pushlightuserdata(info->L,info);
lua_pushnil(info->L);
lua_settable(info->L,-3);
// get the function and call it, passing in the table as the
argument
lua_getfield(info->L,-1,FunctionField);
lua_getfield(info->L,-2,AsyncField);
lua_getfield(info->L,-3,DataField);
if( lua_pcall(info->L,2,0,0) )
{
const char* msg = lua_tostring(info->L, -1);
lua_pop(info->L, 1);
if( msg ) std::cout << "error : " << msg << std::endl;
else std::cout << "error : NULL"<< std::endl;
}
}
public:
int BeginCall( lua_State* L )
{
AsyncInfo* info = new AsyncInfo();
info->L = L;
lua_getglobal(L, AsyncInfoTable);
// key is light user data
lua_pushlightuserdata(L,info);
// info table is
lua_newtable(L);
// function
lua_pushvalue(L,2);
lua_setfield(L,-2,FunctionField);
// async
lua_pushvalue(L,1);
lua_setfield(L,-2,AsyncField);
// data
lua_pushvalue(L,3);
lua_setfield(L,-2,DataField);
lua_settable(L,-3);
CallAsync(info);
return 1;
}
int EndCall( lua_State* L )
{
// this would return a result or data, for right now return
nothing...
return 0;
}
};