Установка пользовательских данных в качестве пространства имен в 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: Для протокола: мне действительно нужно сохранить пользовательские данные конфигурации как есть, потому что они привязаны к структуре C. Как следствие, меня не беспокоит «потеря» состояния Lua или объявленных переменных между разными средами.

Добавление следующей информации. Вот как создаются пользовательские данные конфигурации:

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.


person Agustín Cordes    schedule 15.02.2011    source источник


Ответы (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);
}
person jpjacobs    schedule 15.02.2011
comment
Извините, боюсь, это не совсем так. Помните, что у меня уже есть созданные пользовательские данные конфигурации. Таким образом, каждый раз, когда пользователь устанавливает или получает поле конфигурации, на самом деле я обмениваюсь данными между своей собственной структурой C. - person Agustín Cordes; 15.02.2011
comment
На самом деле, я могу использовать ваше решение, но мне приходится просматривать результирующую таблицу из вызова my_config.cfg. Это не совсем то, что я имел в виду (как я объяснил в своем редактировании), но я думаю, что это можно сделать, если нет лучших предложений. Спасибо! - person Agustín Cordes; 16.02.2011
comment
Но подождите, конфигурация — это простая таблица, не так ли? Потому что вы продолжаете называть это пользовательскими данными. В моем примере я просто использую новую таблицу, вы можете получить свою таблицу конфигурации из реестра или из таблицы глобальных параметров используемого вами lua_State, не так ли? - person jpjacobs; 16.02.2011
comment
Нет, в том-то и дело; см. новый код, который я разместил выше. Конфиг - это пользовательские данные с метатаблицей и всем остальным. Таким образом, каждый раз, когда пользователь обращается к config, __index и __newindex запускаются в C. - person Agustín Cordes; 16.02.2011
comment
Насколько я знаю, пользовательские данные не могут быть установлены в качестве среды в Lua. Ссылка всегда говорит «таблица». Итак, я предполагаю, что вопрос таков: вы действительно хотите использовать этот userdata напрямую или было бы проще просто setfenv создать таблицу для чанка и прочитать его содержимое после его вызова? - person jpjacobs; 16.02.2011
comment
Именно поэтому ваш ответ дал мне пищу для размышлений. Я тоже теперь думаю, что просто невозможно использовать userdatum в качестве среды... Я надеялся на ярлык, но нет. В любом случае, я голосую за это! Спасибо! - person Agustín Cordes; 16.02.2011