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