From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp48.i.mail.ru (smtp48.i.mail.ru [94.100.177.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 24A9544643A for ; Tue, 13 Oct 2020 02:23:08 +0300 (MSK) From: Alexander Turenko Date: Tue, 13 Oct 2020 02:23:10 +0300 Message-Id: <78be0c27f3d7f28da615c98603889551a72cfca2.1602541394.git.alexander.turenko@tarantool.org> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH v3 03/16] module api/lua: add luaL_iscdata() function List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Vladislav Shpilevoy Cc: tarantool-patches@dev.tarantool.org, Alexander Turenko 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 --- src/exports.h | 1 + src/lua/utils.c | 6 +++ src/lua/utils.h | 20 ++++++++++ test/app-tap/module_api.c | 22 +++++++++++ test/app-tap/module_api.test.lua | 63 +++++++++++++++++++++++++++++++- 5 files changed, 111 insertions(+), 1 deletion(-) diff --git a/src/exports.h b/src/exports.h index 7861bb529..01c1aa83e 100644 --- a/src/exports.h +++ b/src/exports.h @@ -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) diff --git a/src/lua/utils.c b/src/lua/utils.c index 399bec6c6..3e1c491f8 100644 --- a/src/lua/utils.c +++ b/src/lua/utils.c @@ -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) { diff --git a/src/lua/utils.h b/src/lua/utils.h index 7e02a05f2..e80e2b1a2 100644 --- a/src/lua/utils.h +++ b/src/lua/utils.h @@ -78,6 +78,26 @@ luaL_pushuuid(struct lua_State *L); /** \cond public */ +/** + * Checks whether a value on the Lua stack is a cdata. + * + * Unlike () 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 diff --git a/test/app-tap/module_api.c b/test/app-tap/module_api.c index 12d20e886..fa5388ba0 100644 --- a/test/app-tap/module_api.c +++ b/test/app-tap/module_api.c @@ -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, res == exp); + 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} }; diff --git a/test/app-tap/module_api.test.lua b/test/app-tap/module_api.test.lua index 08e8add35..0231dc3b0 100755 --- a/test/app-tap/module_api.test.lua +++ b/test/app-tap/module_api.test.lua @@ -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) -- 2.25.0