2

Despite searching hard, i couldn't find a valid Lua C API example for calling a Lua function returning custom data from C function. For example, I have register function "GetMyVector" and then I'm calling that from lua to retrive informations from C, what I got is a table but what I want is something like access to access variable from struct like in C, for example:

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)

my C function pushing vector in 3 dimensional array by 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
  • "If you have any tutorial & info about that, please paste lnk below i'll appreciate it." Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it. Commented Mar 28, 2015 at 21:41
  • yeah, I manage to fix that, but honestly I have no clue what to do because I have no clue how to name that either, cannot find any info of this to step a bit and solve that problem. Commented Mar 28, 2015 at 21:53

2 Answers 2

1

You probably want lua_settable. It allows to set any keys for the table. If the key is literal you can get data by x["i"] or by x.i . The code should be something like

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;
}
Sign up to request clarification or add additional context in comments.

Comments

0

It's a little bit extended, but thanks to @geov I have found what I was looking for, it's kinda similar to properties style like in C# i think, here you go the solution:

#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 */
}

Comments