Skip to content

Instantly share code, notes, and snippets.

@rtsisyk
Created July 29, 2013 09:49
Show Gist options
  • Save rtsisyk/6103290 to your computer and use it in GitHub Desktop.
Save rtsisyk/6103290 to your computer and use it in GitHub Desktop.
An example how to work with CDATA (LuaJIT FFI) objects using lua_State
void *
luaL_pushcdata(struct lua_State *L, uint32_t ctypeid, uint32_t size)
{
/*
* ctypeid is actually has CTypeID type.
* CTypeId is defined somewhere inside luajit's internal headers
* which should not be included in init.h header.
*/
static_assert(sizeof(ctypeid) == sizeof(CTypeID),
"sizeof(ctypeid) == sizeof(CTypeID)");
CTState *cts = ctype_cts(L);
CType *ct = ctype_raw(cts, ctypeid);
CTSize sz;
lj_ctype_info(cts, ctypeid, &sz);
GCcdata *cd = lj_cdata_new(cts, ctypeid, size);
TValue *o = L->top;
setcdataV(L, o, cd);
lj_cconv_ct_init(cts, ct, sz, (uint8_t *) cdataptr(cd), o, 0);
incr_top(L);
return cdataptr(cd);
}
void *
luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid,
const char *ctypename)
{
/* Calculate absolute value in the stack. */
if (idx < 0)
idx = lua_gettop(L) + idx + 1;
if (lua_type(L, idx) != LUA_TCDATA) {
luaL_error(L, "expected cdata as %d argument", ctypename, idx);
return NULL;
}
GCcdata *cd = cdataV(L->base + idx - 1);
*ctypeid = cd->ctypeid;
return (void *)cdataptr(cd);
}
uint32_t
tarantool_lua_ctypeid(struct lua_State *L)
{
int idx = lua_gettop(L);
CTypeID ctypeid;
GCcdata *cd;
/* Get ref to ffi.typeof */
luaL_loadstring(L, "return require('ffi').typeof");
/* lua_call must be wrapped by try .. catch */
try {
lua_call(L, 0, 1);
if (lua_gettop(L) > 1 || !lua_isfunction(L, 1))
goto fail;
/* Push the first argument to ffi.typeof */
lua_pushstring(L, ctypename);
/* Call ffi.typeof() */
lua_call(L, 1, 1);
} catch(...) {
goto fail;
}
/* Returned type should be LUA_TCDATA with CTID_CTYPEID */
if (lua_type(L, 1) != LUA_TCDATA)
goto fail;
cd = cdataV(L->base);
if (cd->ctypeid != CTID_CTYPEID)
goto fail;
ctypeid = *(CTypeID *)cdataptr(cd);
lua_settop(L, idx);
return ctypeid;
fail:
lua_settop(L, idx);
panic("lua call to ffi.typeof failed");
}
struct request;
static const struct request *
lbox_checkrequest(struct lua_State *L, int idx)
{
uint32_t ctypeid;
void *cdata = luaL_checkcdata(L, idx, &ctypeid, "struct request");
if (ctypeid == CTID_STRUCT_REQUEST ||
ctypeid == CTID_CONST_STRUCT_REQUEST) {
return (const struct request *) cdata;
} else if (ctypeid == CTID_CONST_STRUCT_REQUEST_REF ||
ctypeid == CTID_CONST_STRUCT_REQUEST_PTR ||
ctypeid == CTID_STRUCT_REQUEST_REF ||
ctypeid == CTID_STRUCT_REQUEST_PTR) {
return *(const struct request **) cdata;
} else {
luaL_error(L, "expected 'struct request' as %d argument", idx);
return NULL;
}
}
static void
lbox_pushrequest(struct lua_State *L, const struct request *request)
{
void *cdata = luaL_pushcdata(L, CTID_CONST_STRUCT_REQUEST_REF,
sizeof(request));
*(const struct request **) cdata = request;
}
/* Get CTIDs using calls to ffi.typeof() */
CTID_STRUCT_REQUEST = tarantool_lua_ctypeid(L, "struct request");
CTID_STRUCT_REQUEST_PTR = tarantool_lua_ctypeid(L, "struct request *");
CTID_STRUCT_REQUEST_REF = tarantool_lua_ctypeid(L, "struct request &");
CTID_CONST_STRUCT_REQUEST = tarantool_lua_ctypeid(L, "const struct request");
CTID_CONST_STRUCT_REQUEST_PTR = tarantool_lua_ctypeid(L, "const struct request *");
CTID_CONST_STRUCT_REQUEST_REF = tarantool_lua_ctypeid(L, "const struct request &");
Execute ffi.cdef before first call to tarantool_lua_ctypeid:
ffi.cdef([[
/* from request.h */
struct request
{
/* Some members */
};
]])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment