Установка пользовательских данных в качестве пространства имен в Lua
Я исследовал эту тему и попробовал различные подходы, но я не могу реализовать то поведение, которое я имею в виду (я даже не уверен, что это возможно). По сути, у меня есть несколько объектов пользовательских данных, созданных в C, доступ к которым можно получить с помощью их метатаблицы, например:
main.lua
config.display_width = 1280
То, что я хотел бы сделать, это "принудительно" настроить пространство имен конфигурации для конкретного сценария. Как вы уже догадались, мне нужно защитить файл конфигурации, чтобы пользователи могли иметь дело только с конфигурируемым параметром. Как это:
Config.lua
display_width = 1280
И я знаю, что должен сделать что-то подобное в C:
// Register the config metatable and its methods
luaL_loadfile(L, "my_config.cfg");
lua_getglobal(L, "config"); // Is this necessary?
lua_setfenv(L, -2); // I know this has to be used, but how?
lua_pcall(L, 0, 0, 0);
Заранее спасибо, этот сводит меня с ума!
PS: для записи, мне действительно нужно сохранить пользовательские данные конфигурации, как они есть, потому что они связаны со структурой Си. Следовательно, я не беспокоюсь о "потере" состояния Lua или объявленных переменных между различными средами.
Добавляем следующую информацию. Вот как создается конфигурация userdata:
const struct luaL_Reg metaconfig[] =
{
{"__index", l_get},
{"__newindex", l_set},
{NULL, NULL}
};
lua_newuserdata(L, sizeof(void *));
luaL_newmetatable(L, "metaconfig");
luaL_register(L, NULL, metaconfig);
lua_setmetatable(L, -2);
lua_setglobal(L, "config");
Поэтому каждый раз, когда пользователь устанавливает или получает значения из пользовательских данных конфигурации, я обновляю структуру C через __index
или же__newindex
методы.
1 ответ
Вам на самом деле не нужно глобальное представление таблицы конфигурации, вы также можете сделать это с помощью lua_ref.
Здесь это работает, как и ожидалось (я думаю):
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
int main (void){
int idxConfig, res;
lua_State *L = luaL_newstate();
if ((res = luaL_loadfile(L,"my_config.cfg")) != 0){//Load file
printf("Got error code %d loading file my_config.cfg, exiting",res);
exit(-1);
}
lua_newtable(L); // new config table
lua_pushvalue(L,-1);// duplicate table
idxConfig = lua_ref(L,LUA_REGISTRYINDEX); // take a reference to the table (pops it)
lua_setfenv(L,-2); // pop table, set as environment for loaded chunk
lua_call(L,0,0); // load config -- nothing on stack
lua_rawgeti(L,LUA_REGISTRYINDEX,idxConfig); //push config table
lua_getfield(L,1,"display"); //read out "display"
lua_Integer disp_width = lua_tointeger(L,-1);
printf("Display width = %d",(int) disp_width);
lua_close(L);
exit(0);
}