在Lua中将userdata设置为命名空间

发布于 2024-10-17 15:02:06 字数 1114 浏览 2 评论 0原文

我研究了这个主题并尝试了各种方法,但我无法实现我想到的行为(我什至不确定它是否可能)。基本上,我有几个用 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");

因此每次用户从配置用户数据设置或获取值时,我都会通过 __index__newindex 方法更新 C 结构。

I have researched this subject and tried various approaches but I can't implement the behavior I have in mind (I'm not even sure it's possible). Basically, I have several userdata objects created in C that can be accessed by their metatable, like this:

Main.lua

config.display_width = 1280

What I'd like to do is to "force" the config namespace to a specific script. You've guessed it, I need to protect a configuration file so that users are restricted to deal only with the config metatable. Like this:

Config.lua

display_width = 1280

And I know I have to do something like this in 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);

Thank you in advance, this one is driving me crazy!

PS: For the record, I really need to keep the config userdata as it is because it's binded to a C structure. In consequence, I'm not concerned about "losing" the Lua state or declared variables between different environments.

Adding the following information. This is how the config userdata is being created:

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");

So every time the user sets or gets values from the config userdata I update the C structure via the __index or__newindex methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

美人如玉 2024-10-24 15:02:06

你实际上并不需要一个代表配置表的全局变量,你也可以使用 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);
}

you don't really need a global representing the config table, you can do with a lua_ref too.

Here this works as expected (I guess):

#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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文