lua — закрытие магазина в C, вызов асинхронного в C

Мне нужна идея, как я могу хранить закрытия lua, чтобы позже вызывать их асинхронно.

  1. моя первая идея была lua_tocfunction но замыкание не является функцией и не может быть вызвано непосредственно из C
  2. Вторая идея состояла в том, чтобы сохранить закрытие в метатаблице, чтобы я мог нажать его и вызвать позже, но, похоже, я не могу копия закрытие (Error: attempt to index a function value).

Поэтому мне нужна ваша помощь, пожалуйста. Как я могу хранить закрытие?

Я признаю, что я не совсем понял, почему существует __index поле в моем lua ctor, как я скопировал эту часть откуда-то.

Кстати: программа без onrender работал как положено. Я использую Qt GUI и Луа-состояния закрыты, после основной цикл qt, поэтому созданное окно не будет удалено __gc после сценария.

bootstrap.lua

local w = w_render() -- create window object
w:show()

w:onrender(function()
print('render')
end)

w_lua.cpp

// chlua_* are helper macros/templates/methods
// 1: self
// 2: render closure

int w_render_onrender(lua_State *L) {
auto *self = chlua_this<GLWindow *>(L, 1, w_render_table);

lua_pushvalue(L, 2); // copy closure to top
lua_setfield(L, 2, "onrender_cb"); // save closure in metatable
// !!! ERROR: attempt to index a function valueself->onrender([L](){
lua_getfield(L, 2, "onrender_cb");
qDebug() << "onrender";
lua_call(L, 0, 0);
});

return 0;
}

// Creates the object
int w_render(lua_State *L) {
auto *&self = chlua_newuserdata<GLWindow *>(L);
self = new GLWindow;

if (luaL_newmetatable(L, w_render_table)) {
luaL_setfuncs(L, w_render_methods, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
}

lua_setmetatable(L, -2);
return 1;
}

1

Решение

Похоже, ваша проблема связана с использованием неправильных индексов и попыткой установить / получить поля для неправильного объекта lua в стеке. Предполагая, что udata представляет ваш GLWindow * сначала следует закрытие lua, затем попробуйте изменить код следующим образом:

int w_render_onrender(lua_State *L)
{
luaL_checkudata(L, 1, w_render_table);
luaL_checktype(L, 2, LUA_TFUNCTION);
auto *self = chlua_this<GLWindow *>(L, 1, w_render_table);

lua_getmetatable(L, 1);
lua_insert(L, -2);      // GLWindow GLWindow_mt lua_closure
lua_setfield(L, -2, "onrender_cb"); // save closure in metatableself->onrender([L]()
{
luaL_checkudata(L, 1, w_render_table);
// assuming GLWindow udata is self and onrender_cb is your lua closure above
// access GLWindow.onrender_cb through GLWindows's metatable
lua_getfield(L, 1, "onrender_cb");
qDebug() << "onrender";
luaL_checktype(L, -1, LUA_TFUNCTION); // Just to be sure
lua_call(L, 0, 0);
});

return 0;
}

Редактировать: Подумав об этом еще немного, возможно, имеет смысл создать ссылку на lua, используя luaL_ref, Таким образом, вам не нужно заботиться о том, что происходит в стеке, когда self->onrender на самом деле работает, что я предполагаю, является асинхронным:

int w_render_onrender(lua_State *L)
{
luaL_checkudata(L, 1, w_render_table);
luaL_checktype(L, 2, LUA_TFUNCTION);
auto *self = chlua_this<GLWindow *>(L, 1, w_render_table);

auto lua_cb = luaL_ref(L, LUA_REGISTRYINDEX);
// just to check that what's on the stack shouldn't matter
lua_settop(L, 0);

self->onrender([L, lua_cb]()
{
lua_rawgeti(L, LUA_REGISTRYINDEX, lua_cb);
luaL_checktype(L, -1, LUA_TFUNCTION); // Just to be sure
qDebug() << "onrender";
lua_call(L, 0, 0);
luaL_unref(L, LUA_REGISTRYINDEX, lua_cb); // assuming you're done with it
});

return 0;
}
1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]