Skip to content
Snippets Groups Projects
Unverified Commit 6a63b7c0 authored by Alexander Turenko's avatar Alexander Turenko
Browse files

module api/lua: add luaL_iscdata() function

It is useful to provide a module specific error when cdata expected, but
a value of another type is passed.

Alternative would be using of lua_type() to check against LUA_TCDATA,
but this constant is not exposed for modules. See more in the
luaL_iscdata() API comment.

Part of #5273
parent c6117909
No related branches found
No related tags found
No related merge requests found
......@@ -356,6 +356,7 @@ EXPORT(luaL_findtable)
EXPORT(luaL_getmetafield)
EXPORT(luaL_gsub)
EXPORT(luaL_iscallable)
EXPORT(luaL_iscdata)
EXPORT(luaL_loadbuffer)
EXPORT(luaL_loadbufferx)
EXPORT(luaL_loadfile)
......
......@@ -113,6 +113,12 @@ luaL_pushuuid(struct lua_State *L)
return luaL_pushcdata(L, CTID_UUID);
}
int
luaL_iscdata(struct lua_State *L, int idx)
{
return lua_type(L, idx) == LUA_TCDATA;
}
void *
luaL_checkcdata(struct lua_State *L, int idx, uint32_t *ctypeid)
{
......
......@@ -78,6 +78,26 @@ luaL_pushuuid(struct lua_State *L);
/** \cond public */
/**
* Checks whether a value on the Lua stack is a cdata.
*
* Unlike <luaL_checkcdata>() this function does not raise an
* error. It is useful to raise a domain specific error.
*
* Lua API and module API don't expose LUA_TCDATA constant.
* We have no guarantee that this constant will remain the same in
* future LuaJIT versions. So this function should be used in
* modules instead of `lua_type(L, idx) == LUA_TCDATA`.
*
* @param L Lua state.
* @param idx Acceptable index on the Lua stack.
*
* @retval 1 If the value at the given index is a cdata.
* @retval 0 Otherwise.
*/
LUA_API int
luaL_iscdata(struct lua_State *L, int idx);
/**
* @brief Push cdata of given \a ctypeid onto the stack.
* CTypeID must be used from FFI at least once. Allocated memory returned
......
......@@ -455,6 +455,27 @@ test_iscallable(lua_State *L)
return 1;
}
static int
test_iscdata(struct lua_State *L)
{
assert(lua_gettop(L) == 2);
int exp = lua_toboolean(L, 2);
/* Basic test. */
int res = luaL_iscdata(L, 1);
int ok = res == exp;
assert(lua_gettop(L) == 2);
/* Use negative index. */
res = luaL_iscdata(L, -2);
ok = ok && res == exp;
assert(lua_gettop(L) == 2);
lua_pushboolean(L, ok);
return 1;
}
/* {{{ test_box_region */
/**
......@@ -562,6 +583,7 @@ luaopen_module_api(lua_State *L)
{"test_state", test_state},
{"test_tostring", test_tostring},
{"iscallable", test_iscallable},
{"iscdata", test_iscdata},
{"test_box_region", test_box_region},
{NULL, NULL}
};
......
......@@ -116,8 +116,68 @@ local function test_iscallable(test, module)
end
end
local function test_iscdata(test, module)
local ffi = require('ffi')
ffi.cdef([[
struct foo { int bar; };
]])
local cases = {
{
obj = nil,
exp = false,
description = 'nil',
},
{
obj = 1,
exp = false,
description = 'number',
},
{
obj = 'hello',
exp = false,
description = 'string',
},
{
obj = {},
exp = false,
description = 'table',
},
{
obj = function() end,
exp = false,
description = 'function',
},
{
obj = ffi.new('struct foo'),
exp = true,
description = 'cdata',
},
{
obj = ffi.new('struct foo *'),
exp = true,
description = 'cdata pointer',
},
{
obj = ffi.new('struct foo &'),
exp = true,
description = 'cdata reference',
},
{
obj = 1LL,
exp = true,
description = 'cdata number',
},
}
test:plan(#cases)
for _, case in ipairs(cases) do
test:ok(module.iscdata(case.obj, case.exp), case.description)
end
end
local test = require('tap').test("module_api", function(test)
test:plan(25)
test:plan(26)
local status, module = pcall(require, 'module_api')
test:is(status, true, "module")
test:ok(status, "module is loaded")
......@@ -143,6 +203,7 @@ local test = require('tap').test("module_api", function(test)
test:test("pushcdata", test_pushcdata, module)
test:test("iscallable", test_iscallable, module)
test:test("iscdata", test_iscdata, module)
space:drop()
end)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment