Salva riferimento ai dati utente di Lua
-
22-07-2019 - |
Domanda
# 1 Lua:
local test = Test();
# 2 C:
//creating "lua's test"
luaL_newmetatable(L, "someTable");
lua_userdata *userData = (lua_userdata *)lua_newuserdata(L, sizeof(lua_userdata));
luaL_getmetatable(L, "someTable");
lua_setmetatable(L, -2);
# 3 Lua:
function test.newMethod()
end
# 4 C:
//this part is not executed from Lua
//what i have to have here from #2 to call "test.newMethod" and how to call it?
//if userdata would be on stack i guess i could:
luaL_getmetafield (L, 1, "newMethod");
lua_call(L, 0, 0);
//but because this part is not executed by Lua call its not on stack.
A cura:
proverà a spiegare più semplicemente in pseudo codice:
Lua:
local test = Object();
C:
int Object(){
...
somePointer = luaL_newmetatable(...); //how to get this "somePointer"? maybe luaL_ref?
push ...
}
Lua: crea un nuovo metodo
function test.newMethod()
...
end
In C alcuni eventi (diciamo timer) attivano il metodo C
void triggeredCMethod(){
//here i need to call test.newMethod
//if i would have here 'somePointer' and could push it to Lua stack i could find and call newMethod
}
quindi la domanda è: come in C archiviare il puntatore su un oggetto Lua (spero di averne bisogno), ottenere l'oggetto Lua con quel puntatore e chiamare il metodo in esso
Soluzione
Suppongo che tu voglia essere in grado di chiamare funzioni aggiunte dinamicamente. Questo codice dovrebbe spiegarlo in modo relativamente semplice. Nota Non faccio molti controlli degli errori e faccio alcune ipotesi, non copio incollalo come soluzione.
typedef struct
{
int number;
int reference;
lua_State *L;
} TestUserdata;
static int m_newindex( lua_State *L )
{
/* This is passed three values, first ( at -3 ) is the object, bring this to the front */
lua_getfenv( L, -3 );
/* Now bring the second arg forward, the key */
lua_pushvalue( L, -3 );
/* And the third arg, the value */
lua_pushvalue( L, -3 );
/* And we're done */
lua_rawset( L, -3 );
return 0;
}
static int m_tostring( lua_State *L )
{
lua_pushstring( L, "TestUserdata" );
return 1;
}
static int callobject( lua_State *L )
{
/* Grab the object passed, check it's the right type */
TestUserdata *data = luaL_checkudata( L, 1, "TestUserdata" );
/* Grab the function environment we gave it in createobject, and look in there for newmethod */
lua_getfenv( L, -1 );
lua_pushstring( L, "newmethod" );
lua_rawget( L, -2 );
/* Call the function */
lua_pushinteger( L, data->number );
lua_call( L, 1, 0 );
return 0;
}
static const struct luaL_reg userdata_m[] = {
{ "__newindex", m_newindex },
{ "__tostring", m_tostring },
{ NULL, NULL }
};
int main (int argc, char *argv[])
{
lua_State *L = luaL_newstate();
luaL_openlibs( L );
/* Let's create us a userdatum metatable, and fill it up with goodies */
luaL_newmetatable( L, "TestUserdata" );
/* Use luaL_register to fill up the metatable for us */
luaL_register( L, NULL, userdata_m );
lua_pop( L, 1 ); /* Clean up the stack, we won't need the metatable left here */
TestUserdata *data = lua_newuserdata( L, sizeof( TestUserdata ) );
lua_pushvalue( L, -1 ); /* Copy for luaL_ref */
int ref = luaL_ref( L, LUA_REGISTRYINDEX );
data->reference = ref;
data->number = 42;
data->L = L;
/* Load the metatable from before and 'give' it to this userdatum */
luaL_getmetatable( L, "TestUserdata" );
lua_setmetatable( L, -2 );
/* Give this object an empty function environment */
lua_newtable( L );
lua_setfenv( L, -2 );
lua_setglobal( L, "test" );
luaL_dostring( L, "function test.newmethod( num ) print( num ) end" );
/* Now provided we have the object, we can call any method defined anywhere */
lua_rawgeti( data->L, LUA_REGISTRYINDEX, data->reference );
lua_getfenv( data->L, -1 );
lua_pushstring( data->L, "newmethod" );
lua_rawget( data->L, -2 );
lua_remove( data->L, -2 );
if( lua_isfunction( data->L, -1 ) == 1 )
{
lua_pushinteger( data->L, data->number );
lua_pcall( data->L, 1, 0, 0 );
}
lua_close( L );
return 0;
}
Verifica, penso che sia quello che stai cercando.
Altri suggerimenti
Se tutto ciò che vuoi è chiamare la funzione Lua `test.newMethod () ', allora penso che tu voglia qualcosa nell'ordine di questo:
lua_getglobal(L, "test");
lua_getfield(L, -1, "newMethod");
lua_call(L, 0, 0);
Non penso che tu debba fare confusione con un metatable o un userdata.
Tuttavia la forza della tua domanda non mi è del tutto chiara ...