LuaJit - 从模块/包中获取元数据并将其分配给userdata

时间:2014-09-07 23:31:45

标签: c lua luajit user-data metatable

假设我有一个自定义结构vector2_t的metatable,它位于模块 mymod 中,如下所示:

local mymod = {}

local ffi = require("ffi")
local C = ffi.C

ffi.cdef[[
    typedef struct
    {
        double x;
        double y;
    } vector2_t;
]]

local vector2_t

vector2_t = ffi.metatype("vector2_t", {
    __eq = function(lhs, rhs)
        if lhs.x == rhs.x and lhs.y == rhs.y
        then return true else return false end
    end
    -- Member functions follow...
})

vcmp.vector2 = vector2_t

-- I use this method because the script is integrated in C/C++ as a string and not
-- as a file and I need a constant name that isn't decided by the file name

package.preload["mymod"] = function(mod) return mymod end

在另一个脚本中,我有这个回调/事件监听器函数,它必须接收vector2_t作为它的参数:

local mymod =  require "mymod"

local some_pos = mymod.vector2(32, 29.7)

-- That pos argument must be an instance of mymod.vector2_t
function position_update(pos)
    print("New Pos: " .. pos.x .. ", " .. pos.y .. "\n")
    some_pos.x = pos.x
    some_pos.y = pos.y
end

现在,我必须从C / C ++调用该回调/事件监听器函数,并将该vector2_t的实例(以及它的关联metatable)作为该函数的参数传递。

typedef struct
{
    double x;
    double y;
} vector2_t;

void call_position_update(lua_State* L, double x, double y)
{
    // Retrieve the function
    lua_getglobal(L, "position_update");

    // Validate it
    if (!lua_isfunction(L, lua_gettop(L)))
    {
        lua_pop(L, 1);
        return;    
    }

    // Create an instance of vector2_t
    vector2_t *pos = (vector2_t *)lua_newuserdata(L, sizeof(vector2_t));

    // Assign the values to the new instance
    pos->x = x;
    pos->y = y;

    // How do I get the meta table vector2_t on to the stack?
    // Reach to the module somehow...

    //  Get the meta table from the module
    luaL_getmetatable(L, "vector2_t");
    // Assign the meta table to the vector2_t instance already on the stack
    lua_setmetatable(L, -2);

    // I'm assuming that the vector2_t instance is already on the stack so there's nothing else to push

    // Call the function with 1 argument which should be that vector2_t onto the stack
    if (!lua_pcall(L, 1, 0, 0))
    {
        printf("Error calling function 'position_update': %s\n", lua_tostring(_Lua, -1));
    }
}

我有点迷失,我不知道如何将vector2_t的实例作为函数参数。我很抱歉发布了这么多代码,我想确保我的解释正确。

1 个答案:

答案 0 :(得分:0)

cdata和userdata完全不同。他们唯一的互动是你可以得到一个指向userdata的FFI void*指针。值得注意的是,cdata对象没有C API。混合它们肯定会引起很多麻烦。

选择Lua C API或FFI,并尽可能坚持下去。


直接回答你的问题:

  

如何将该vector2_t的实例作为函数参数

进行传递

对于Lua C API函数,它会像其他值一样在堆栈上传递。请注意,它将是cdata类型的对象,而不是userdata对象。值得注意的是,你无法获得指向它的指针。

  

如何将元表vector2_t放到堆栈上?

您不能,因为您不能在第一个脚本中使外部脚本可以访问元表。 luaL_getmetatable仅适用于使用luaL_newmetatable

创建的元表