Lua从C函数返回自定义数据

时间:2015-03-28 21:32:52

标签: c++ c lua luabind

尽管努力搜索,但我无法找到一个有效的Lua C API示例来调用从C函数返回自定义数据的Lua函数。 例如,我有注册功能" GetMyVector"然后我从lua调用它来从C中检索信息,我得到的是一个表,但我想要的是像在C中那样从struct访问变量,例如:

local x = GetMyVector()
print(x[1]) -- i 
print(x[2]) -- j
print(x[3]) -- k
-- how to access it via like this:
print(x.i)
print(x.j)
print(x.k)

我的C函数通过lua_pushnumber推送三维数组中的向量:

static int GetMyVector(lua_State *L)
{
    vec3_t vec;
    vec[0] = 1;
    vec[1] = 2;
    vec[3] = 3;
    lua_newtable(L);
    lua_pushnumber(L, vec[0]);
    lua_rawseti(L, -2, 1);
    lua_pushnumber(L, vec[1]);
    lua_rawseti(L, -2, 2);
    lua_pushnumber(L, vec[2]);
    lua_rawseti(L, -2, 3);
    return 1;
}

2 个答案:

答案 0 :(得分:1)

你可能想要lua_settable。它允许为表设置任何键。如果密钥是字面值,您可以按x["i"]x.i获取数据。 代码应该类似于

static int GetMyVector(lua_State *L)
{
    vec3_t vec;
    vec[0] = 1;
    vec[1] = 2;
    vec[3] = 3;
    lua_newtable(L);

    lua_pushliteral(L, "i");
    lua_pushnumber(L, vec[0]);
    lua_settable(L, -2);

    lua_pushliteral(L, "j");
    lua_pushnumber(L, vec[1]);
    lua_settable(L, -2);

    lua_pushliteral(L, "k");
    lua_pushnumber(L, vec[2]);
    lua_settable(L, -2);
    return 1;
}

答案 1 :(得分:0)

它有点扩展,但多亏了@geov我找到了我想要的东西,它有点类似于C#中的属性风格我认为,在这里你可以解决方案:

#define MYCLASSNAME "vec"

typedef struct {
    int i, j, k;
} MyVec_t;

typedef int(*Xet_func) (lua_State *L, void *v);

/* member info for get and set handlers */
typedef const struct{
    const char *name;  /* member name */
    Xet_func func;     /* get or set function for type of member */
    size_t offset;     /* offset of member within MyVec_t */
}  Xet_reg_pre;

typedef Xet_reg_pre * Xet_reg;

// properties
static int Get_Int(lua_State *L, void *v) {
    lua_pushnumber(L, *(int*)v);
    return 1;
}

static int Set_Int(lua_State *L, void *v) {
    *(int*)v = luaL_checkinteger(L, 3);
    return 0;
}

static int Get_Number(lua_State *L, void *v) {
    lua_pushnumber(L, *(lua_Number*)v);
    return 1;
}

static int Set_Number(lua_State *L, void *v) {
    *(lua_Number*)v = luaL_checknumber(L, 3);
    return 0;
}

static int Get_String(lua_State *L, void *v) {
    lua_pushstring(L, (char*)v);
    return 1;
}

static void Property_Add(lua_State *L, Xet_reg l)
{
    for (; l->name; l++) {
        lua_pushstring(L, l->name);
        lua_pushlightuserdata(L, (void*)l);
        lua_settable(L, -3);
    }
}

static int Property_Call(lua_State *L)
{
    Xet_reg m = (Xet_reg)lua_touserdata(L, -1);  
    lua_pop(L, 1);                               
    luaL_checktype(L, 1, LUA_TUSERDATA);
    return m->func(L, (void *)((char *)lua_touserdata(L, 1) + m->offset));
}

static int index_handler(lua_State *L)
{
    /* stack has userdata, index */
    lua_pushvalue(L, 2);                     /* dup index */
    lua_rawget(L, lua_upvalueindex(1));      /* lookup member by name */
    if (!lua_islightuserdata(L, -1)) {
        lua_pop(L, 1);                         /* drop value */
        lua_pushvalue(L, 2);                   /* dup index */
        lua_gettable(L, lua_upvalueindex(2));  /* else try methods */
        if (lua_isnil(L, -1))                  /* invalid member */
            luaL_error(L, "cannot get member '%s'", lua_tostring(L, 2));
        return 1;
    }
    return Property_Call(L);                      /* call get function */
}

static int newindex_handler(lua_State *L)
{
    /* stack has userdata, index, value */
    lua_pushvalue(L, 2);                     /* dup index */
    lua_rawget(L, lua_upvalueindex(1));      /* lookup member by name */
    if (!lua_islightuserdata(L, -1))         /* invalid member */
        luaL_error(L, "cannot set member '%s'", lua_tostring(L, 2));
    return Property_Call(L);                      /* call set function */
}

static MyVec_t *CheckMyVec(lua_State *L, int index) // get data
{
    MyVec_t *p;
    luaL_checktype(L, index, LUA_TUSERDATA);
    p = (MyVec_t *)luaL_checkudata(L, index, MYCLASSNAME);
    return p;
}

static MyVec_t *PushMyVec(lua_State *L) // push data
{
    MyVec_t *p = (MyVec_t *)lua_newuserdata(L, sizeof(MyVec_t));
    luaL_getmetatable(L, MYCLASSNAME);
    lua_setmetatable(L, -2);
    return p;
}

static int MyVec_Create(lua_State *L)   // C function which will push data
{
    MyVec_t *p;
    p = PushMyVec(L);
    p->i = luaL_checkinteger(L, 1);
    p->j = luaL_checkinteger(L, 2);;
    p->k = luaL_checkinteger(L, 3);;
    return 1;
}

static int MyVec_destroy(lua_State *L)
{
    MyVec_t *p = (MyVec_t *)lua_touserdata(L, 1);
    return 0;
}

static int MyVec_Position(lua_State *L)
{
    MyVec_t *p = CheckMyVec(L, 1);
    double   x = p->i;
    double   y = p->j;
    double   z = p->k;
    if (lua_gettop(L) > 1) {
        p->i = luaL_checknumber(L, 2);
        p->j = luaL_checknumber(L, 3);
        p->k = luaL_checknumber(L, 4);
    }
    lua_pushnumber(L, x);
    lua_pushnumber(L, y);
    lua_pushnumber(L, z);
    return 2;
}


static const luaL_Reg myvec_meta_methods[] = {
    { "__gc", MyVec_destroy },
    { 0, 0 }
};

static const luaL_Reg myvec_methods[] = {
    { "create",  MyVec_Create },
    { "position", MyVec_Position },
    { 0, 0 }
};

static const Xet_reg_pre MyVec_get[] = {
    { "i", Get_Int, offsetof(MyVec_t, i) },
    { "j", Get_Int, offsetof(MyVec_t, j) },
    { "k", Get_Int, offsetof(MyVec_t, k) },
    { 0, 0 }
};

static const Xet_reg_pre MyVec_set[] = {
    { "i", Set_Int, offsetof(MyVec_t, i) },
    { "j", Set_Int, offsetof(MyVec_t, j) },
    { "k", Set_Int, offsetof(MyVec_t, k) },
    { 0, 0 }
};


int MyVec_Register(lua_State *L)
{
    int metatable, methods;

    /* create methods table, & add it to the table of globals */
    luaL_openlib(L, MYCLASSNAME, myvec_methods, 0);
    methods = lua_gettop(L);

    /* create metatable for MyVec_t, & add it to the registry */
    luaL_newmetatable(L, MYCLASSNAME);
    luaL_openlib(L, 0, myvec_meta_methods, 0);  /* fill metatable */
    metatable = lua_gettop(L);

    lua_pushliteral(L, "__metatable");
    lua_pushvalue(L, methods);              /* dup methods table*/
    lua_rawset(L, metatable);               /* hide metatable:
                                            metatable.__metatable = methods */
    lua_pushliteral(L, "__index");
    lua_pushvalue(L, metatable);            /* upvalue index 1 */
    Property_Add(L, MyVec_get);             /* fill metatable with getters */
    lua_pushvalue(L, methods);              /* upvalue index 2 */
    lua_pushcclosure(L, index_handler, 2);
    lua_rawset(L, metatable);               /* metatable.__index = index_handler */

    lua_pushliteral(L, "__newindex");
    lua_newtable(L);                        /* table for members you can set */
    Property_Add(L, MyVec_set);             /* fill with setters */
    lua_pushcclosure(L, newindex_handler, 1);
    lua_rawset(L, metatable);               /* metatable.__newindex = newindex_handler */

    lua_pop(L, 1);                          /* drop metatable */
    return 1;                               /* return methods on the stack */
}