Сохранение структуры C в реестре Lua

Когда я интегрирую Lua в свою программу на C, я использую указатель static на структуру C для хранения объекта, который мне нужно повторно использовать в методах, которые я привязываю к состоянию Lua.

Однако это не работает, когда я отделяю свою библиотеку Lua от основной программы, поэтому, похоже, мне нужно использовать реестр для хранения моей структуры.

Как мне сохранить указатель на структуру C в реестре Lua?

Это то, что я сейчас делаю:

static augeas *aug = NULL;


static int lua_aug_get(lua_State *L) {
    // Use aug to do something here
    /* return the number of results */
    return 1;
}

struct lua_State *luaopen_augeas(augeas *a) {
    lua_State *L = luaL_newstate();
    aug = a; // this clearly does not work
    luaL_openlibs(L);
    // The methods below will need to access the augeas * struct
    // so I need to push it to the registry (I guess)
    static const luaL_Reg augfuncs[] = {
        { "get", lua_aug_get },
        { "label", lua_aug_label },
        { "set", lua_aug_set },
        { NULL, NULL }
    };

    luaL_newlib(L, augfuncs);
    lua_setglobal(L, "aug");

    return L;
}

Изменить: судя по ответу, который я получил в IRC, мне следует использовать метатаблицу, поэтому я сейчас изучаю это.


person raphink    schedule 24.09.2015    source источник


Ответы (2)


Если реестр не является достаточно безопасным местом для хранения указателя, вы можете использовать его в качестве повышающего значения для определенных функций:

static int lua_aug_get(lua_State *L) {
  augeas *aug = lua_touserdata(L, lua_upvalueindex(1));
  // Do stuff with aug
  return 1;
}

static const luaL_Reg augfuncs[] = {
    { "get", lua_aug_get },
    { "label", lua_aug_label },
    { "set", lua_aug_set },
    { NULL, NULL }
};
lua_createtable(L, 0, 0);
for (size_t i = 0; augfuncs[i].name; i++) {
    lua_pushlightuserdata(L, a);
    lua_pushcclosure(L, augfuncs[i].func, 1);
    lua_setfield(L, -2, augfuncs[i].name);
}

Но можно хранить в реестре. Она недоступна для сценариев, за исключением библиотеки debug, которая обычно не отображается в песочницах. И если другие библиотеки устраивают там эгоистичную неразбериху, у вас все равно будут проблемы.

person user3125367    schedule 24.09.2015

Мне удалось заставить его работать, используя индекс реестра Lua и нажимая указатель как light пользовательские данные:

static const char *Key = "augeas_registry_key"; // The registry key

static augeas *checkaug(lua_State *L) {
  lua_pushlightuserdata(L, (void *)&Key);        // set the registry key
  lua_gettable(L, LUA_REGISTRYINDEX);            // retrieve value
  augeas *aug = (augeas *)lua_touserdata(L, -1); // cast value
  return aug;
}

static int lua_aug_get(lua_State *L) {
  augeas *aug = checkaug(L);
  // Do stuff with aug
  return 1;
}

struct lua_State *luaopen_augeas(augeas *a) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);

    lua_pushlightuserdata(L, (void *)&Key); // set registry key
    lua_pushlightuserdata(L, (void *)a);    // push pointer
    lua_settable(L, LUA_REGISTRYINDEX);     // push to in registry

    static const luaL_Reg augfuncs[] = {
        { "get", lua_aug_get },
        { "label", lua_aug_label },
        { "set", lua_aug_set },
        { NULL, NULL }
    };

    luaL_newlib(L, augfuncs);
    lua_setglobal(L, "aug");

    return L;
}

Это не очень элегантно, учитывая, что используется общий реестр, который может быть доступен для других библиотек, загруженных во время сеанса, поэтому я все еще открыт для лучшего варианта.

person raphink    schedule 24.09.2015