* [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module
@ 2020-09-24 21:00 Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 1/9] module api: export box_tuple_validate Timur Safin
` (8 more replies)
0 siblings, 9 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
This patchset is a 1.10 backport of a 2.X series which was in turn
continuation of patch series which Alexander Turenko has sent before.
The major difference here - is the way how we export symbols:
- in 1.10 there was no `src/exports.h` existing, and we were using
old good `extra/exports` instead.
Issue:
* https://github.com/tarantool/tarantool/issues/5273
('module api: expose everything that is needed for external key_def module')
Branches:
* https://github.com/tarantool/tarantool/tree/tsafin/gh-5273-expand-module-api
(top 7 commits above of 14 @Totktonada's commits)
* https://github.com/tarantool/tarantool/tree/tsafin/gh-5273-expand-module-api-1.10
(last 9 commits above of 16 @Totktonada's commits)
Alexander Turenko (1):
module api: add luaL_iscallable with support of cdata metatype
Timur Safin (8):
module api: export box_tuple_validate
module api: export box_key_def_dup
module api: luaT_newthread
module api: luaL_register_module & luaL_register_type
module api: luaT_temp_luastate & luaT_release_temp_luastate
module api: luaL_checkibuf & luaL_checkconstchar
module api: extend list of public symbols in 1.10
module api: luaL_cdata_iscallable
extra/exports | 22 +++++++
src/box/key_def_api.c | 6 ++
src/box/key_def_api.h | 10 ++++
src/box/tuple.c | 8 +++
src/box/tuple.h | 11 ++++
src/lua/utils.c | 92 +++++++++++++++++++++++++++++
src/lua/utils.h | 99 +++++++++++++++++++++++++++-----
test/app-tap/module_api.c | 10 ++++
test/app-tap/module_api.test.lua | 85 ++++++++++++++++++++++++++-
9 files changed, 327 insertions(+), 16 deletions(-)
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 1/9] module api: export box_tuple_validate
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 2/9] module api: export box_key_def_dup Timur Safin
` (7 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
For external merger we need means to valudate tuple data,
thus exporting `box_tuple_validate` which is simple wrapper
around `tuple_validate_raw` without revealing access to tuple
internals.
Part of #5273
---
src/box/tuple.c | 8 ++++++++
src/box/tuple.h | 11 +++++++++++
2 files changed, 19 insertions(+)
diff --git a/src/box/tuple.c b/src/box/tuple.c
index 1db69e414..d97f6cef5 100644
--- a/src/box/tuple.c
+++ b/src/box/tuple.c
@@ -576,6 +576,14 @@ box_tuple_new(box_tuple_format_t *format, const char *data, const char *end)
return tuple_bless(ret);
}
+int
+box_tuple_validate(box_tuple_format_t *format, box_tuple_t *tuple)
+{
+ return tuple_validate_raw(format, tuple_data(tuple));
+}
+
+/* }}} box_tuple_* */
+
int
tuple_snprint(char *buf, int size, const struct tuple *tuple)
{
diff --git a/src/box/tuple.h b/src/box/tuple.h
index 5c6dc6b8c..afa334eab 100644
--- a/src/box/tuple.h
+++ b/src/box/tuple.h
@@ -284,6 +284,17 @@ box_tuple_t *
box_tuple_upsert(const box_tuple_t *tuple, const char *expr, const
char *expr_end);
+/**
+ * Check tuple data correspondence to the space format.
+ * @param format Format to which the tuple must match.
+ * @param tuple Tuple to validate.
+ *
+ * @retval 0 The tuple is valid.
+ * @retval -1 The tuple is invalid.
+ */
+int
+box_tuple_validate(box_tuple_format_t *format, box_tuple_t *tuple);
+
/** \endcond public */
/**
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 2/9] module api: export box_key_def_dup
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 1/9] module api: export box_tuple_validate Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 3/9] module api: luaT_newthread Timur Safin
` (6 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
Exporting `box_key_def_dup` as accessor to the internal `key_def_dup`
Part of #5273
---
src/box/key_def_api.c | 6 ++++++
src/box/key_def_api.h | 10 ++++++++++
2 files changed, 16 insertions(+)
diff --git a/src/box/key_def_api.c b/src/box/key_def_api.c
index 55fbc53ce..5c775f1a9 100644
--- a/src/box/key_def_api.c
+++ b/src/box/key_def_api.c
@@ -175,6 +175,12 @@ box_key_def_new_ex(box_key_part_def_t *parts, uint32_t part_count)
return key_def;
}
+box_key_def_t *
+box_key_def_dup(const box_key_def_t *key_def)
+{
+ return key_def_dup(key_def);
+}
+
void
box_key_def_delete(box_key_def_t *key_def)
{
diff --git a/src/box/key_def_api.h b/src/box/key_def_api.h
index b85ed7f3c..829871ed9 100644
--- a/src/box/key_def_api.h
+++ b/src/box/key_def_api.h
@@ -153,6 +153,16 @@ box_key_part_def_create(box_key_part_def_t *part);
API_EXPORT box_key_def_t *
box_key_def_new_ex(box_key_part_def_t *parts, uint32_t part_count);
+/**
+ * Duplicate key_def.
+ * \param key_def Original key_def.
+ *
+ * \retval not NULL Duplicate of src.
+ * \retval NULL Memory error.
+ */
+box_key_def_t *
+box_key_def_dup(const box_key_def_t *key_def);
+
/**
* Delete key definition
*
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 3/9] module api: luaT_newthread
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 1/9] module api: export box_tuple_validate Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 2/9] module api: export box_key_def_dup Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 4/9] module api: luaL_register_module & luaL_register_type Timur Safin
` (5 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
Exporting `luaT_newthread` as it's necessary for external merger
Part of #5273
---
src/lua/utils.h | 35 +++++++++++++++++++++++------------
1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/src/lua/utils.h b/src/lua/utils.h
index fe6728986..363d5e908 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -505,6 +505,29 @@ luaT_state(void);
LUA_API const char *
luaT_tolstring(lua_State *L, int idx, size_t *ssize);
+/**
+ * Check whether a Lua object is a function or has
+ * metatable/metatype with a __call field.
+ *
+ * Note: It does not check type of __call metatable/metatype
+ * field.
+ */
+LUA_API int
+luaL_iscallable(lua_State *L, int idx);
+
+
+/**
+ * @brief Creates a new Lua coroutine in a protected frame. If
+ * <lua_newthread> call underneath succeeds, the created Lua state
+ * is on the top of the guest stack and a pointer to this state is
+ * returned. Otherwise LUA_ERRMEM error is handled and the result
+ * is NULL.
+ * @param L is a Lua state
+ * @sa <lua_newthread>
+ */
+struct lua_State *
+luaT_newthread(struct lua_State *L);
+
/** \endcond public */
void
@@ -605,18 +628,6 @@ int
luaL_checkconstchar(struct lua_State *L, int idx, const char **res,
uint32_t *cdata_type_p);
-/**
- * @brief Creates a new Lua coroutine in a protected frame. If
- * <lua_newthread> call underneath succeeds, the created Lua state
- * is on the top of the guest stack and a pointer to this state is
- * returned. Otherwise LUA_ERRMEM error is handled and the result
- * is NULL.
- * @param L is a Lua state
- * @sa <lua_newthread>
- */
-struct lua_State *
-luaT_newthread(struct lua_State *L);
-
int
tarantool_lua_utils_init(struct lua_State *L);
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 4/9] module api: luaL_register_module & luaL_register_type
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
` (2 preceding siblings ...)
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 3/9] module api: luaT_newthread Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 5/9] module api: luaT_temp_luastate & luaT_release_temp_luastate Timur Safin
` (4 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
Exporting `luaL_register_module` & `luaL_register_type`
functions as they needed for external merger
Part of #5273
---
src/lua/utils.h | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/lua/utils.h b/src/lua/utils.h
index 363d5e908..a818e5eee 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -69,6 +69,8 @@ extern struct ibuf *tarantool_lua_ibuf;
/** \cond public */
+struct luaL_Reg;
+
/**
* @brief Checks whether a value on the Lua stack is a cdata.
*
@@ -410,6 +412,8 @@ luaL_checkfield(struct lua_State *L, struct luaL_serializer *cfg, int idx,
luaL_convertfield(L, cfg, idx, field);
}
+/** \cond public */
+
void
luaL_register_type(struct lua_State *L, const char *type_name,
const struct luaL_Reg *methods);
@@ -419,8 +423,6 @@ void
luaL_register_module(struct lua_State *L, const char *modname,
const struct luaL_Reg *methods);
-/** \cond public */
-
/**
* Push uint64_t onto the stack
*
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 5/9] module api: luaT_temp_luastate & luaT_release_temp_luastate
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
` (3 preceding siblings ...)
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 4/9] module api: luaL_register_module & luaL_register_type Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 6/9] module api: luaL_checkibuf & luaL_checkconstchar Timur Safin
` (3 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
Moved `luaT_temp_luastate` & `luaT_release_temp_luastate` from
merger to ustil.c and made them public.
They were necessary for external merger support
Part of #5273
---
src/lua/utils.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
src/lua/utils.h | 35 +++++++++++++++++++++++++++++++++++
2 files changed, 84 insertions(+)
diff --git a/src/lua/utils.c b/src/lua/utils.c
index e555607cf..58c54f8fb 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -1090,6 +1090,55 @@ luaT_newthread(struct lua_State *L)
return L1;
}
+struct lua_State *
+luaT_temp_luastate(int *coro_ref, int *top)
+{
+ if (fiber()->storage.lua.stack != NULL) {
+ /*
+ * Reuse existing stack. In the releasing function
+ * we should drop a stack top to its initial
+ * value to don't exhaust available slots by
+ * many requests in row.
+ */
+ struct lua_State *L = fiber()->storage.lua.stack;
+ *coro_ref = LUA_NOREF;
+ *top = lua_gettop(L);
+ return L;
+ }
+
+ /* Popped by luaL_ref(). */
+ struct lua_State *L = luaT_newthread(tarantool_L);
+ if (L == NULL)
+ return NULL;
+ /*
+ * We should remove the reference to the newly created Lua
+ * thread from tarantool_L, because of two reasons:
+ *
+ * First, if we'll push something to tarantool_L and
+ * yield, then another fiber will not know that a stack
+ * top is changed and may operate on a wrong slot.
+ *
+ * Second, many requests that push a value to tarantool_L
+ * and yield may exhaust available slots on the stack. It
+ * is limited by LUAI_MAXSTACK build time constant (~65K).
+ *
+ * We cannot just pop the value, but should keep the
+ * reference in the registry while it is in use.
+ * Otherwise it may be garbage collected.
+ */
+ *coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX);
+ *top = -1;
+ return L;
+}
+
+void
+luaT_release_temp_luastate(struct lua_State *L, int coro_ref, int top)
+{
+ if (top >= 0)
+ lua_settop(L, top);
+ luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref);
+}
+
int
tarantool_lua_utils_init(struct lua_State *L)
{
diff --git a/src/lua/utils.h b/src/lua/utils.h
index a818e5eee..4eb5ce566 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -530,6 +530,41 @@ luaL_iscallable(lua_State *L, int idx);
struct lua_State *
luaT_newthread(struct lua_State *L);
+/**
+ * Get a temporary Lua state.
+ *
+ * Use case: a function does not accept a Lua state as an argument
+ * to allow using from C code, but uses a Lua value, which is
+ * referenced in LUA_REGISTRYINDEX. A temporary Lua stack is needed
+ * to get and process the value.
+ *
+ * The resulting Lua state has a separate Lua stack, but the same
+ * globals and registry as `tarantool_L` (and all Lua states in
+ * tarantool at the moment of writing this).
+ *
+ * This Lua state should be used only from one fiber: otherwise
+ * one fiber may change the stack and another one will access a
+ * wrong stack slot when it will be scheduled for execution after
+ * yield.
+ *
+ * Return a Lua state on success and set @a coro_ref and @a top.
+ * These values should be passed to
+ * `luaT_release_temp_luastate()`, when the state is not needed
+ * anymore.
+ *
+ * Return NULL and set a diag at failure.
+ */
+struct lua_State *
+luaT_temp_luastate(int *coro_ref, int *top);
+
+/**
+ * Release a temporary Lua state.
+ *
+ * It complements `luaT_temp_luastate()`.
+ */
+void
+luaT_release_temp_luastate(struct lua_State *L, int coro_ref, int top);
+
/** \endcond public */
void
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 6/9] module api: luaL_checkibuf & luaL_checkconstchar
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
` (4 preceding siblings ...)
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 5/9] module api: luaT_temp_luastate & luaT_release_temp_luastate Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 7/9] RFC: module api: extend list of public symbols in 1.10 Timur Safin
` (2 subsequent siblings)
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
Moved `luaL_checkibuf` & `luaL_checkconstchar` to the public
part of module api.
Part of #5273
---
src/lua/utils.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/lua/utils.h b/src/lua/utils.h
index 4eb5ce566..ac6682d80 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -565,6 +565,23 @@ luaT_temp_luastate(int *coro_ref, int *top);
void
luaT_release_temp_luastate(struct lua_State *L, int coro_ref, int top);
+/**
+ * Check if a value on @a L stack by index @a idx is an ibuf
+ * object. Both 'struct ibuf' and 'struct ibuf *' are accepted.
+ * Returns NULL, if can't convert - not an ibuf object.
+ */
+struct ibuf *
+luaL_checkibuf(struct lua_State *L, int idx);
+
+/**
+ * Check if a value on @a L stack by index @a idx is pointer at
+ * char or const char. '(char *)NULL' is also considered a valid
+ * char pointer.
+ */
+int
+luaL_checkconstchar(struct lua_State *L, int idx, const char **res,
+ uint32_t *cdata_type_p);
+
/** \endcond public */
void
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 7/9] RFC: module api: extend list of public symbols in 1.10
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
` (5 preceding siblings ...)
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 6/9] module api: luaL_checkibuf & luaL_checkconstchar Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-29 6:21 ` Alexander Turenko
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 8/9] module api: add luaL_iscallable with support of cdata metatype Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 9/9] module api: luaL_cdata_iscallable Timur Safin
8 siblings, 1 reply; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
Backported exported symbols necessary for extended
module api for the purposes of external merger
Part of #5273
---
| 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
--git a/extra/exports b/extra/exports
index a4ac03530..70b59a0a6 100644
--- a/extra/exports
+++ b/extra/exports
@@ -118,7 +118,10 @@ coio_call
coio_getaddrinfo
luaL_pushcdata
luaL_iscdata
+luaL_iscallable
luaL_checkcdata
+luaL_checkconstchar
+luaL_checkibuf
luaL_setcdatagc
luaL_ctypeid
luaL_cdef
@@ -129,13 +132,16 @@ luaL_checkint64
luaL_touint64
luaL_toint64
luaT_pushtuple
+luaT_newthread
luaT_istuple
luaT_tuple_encode
luaT_tuple_new
luaT_error
luaT_call
luaT_cpcall
+luaT_release_temp_luastate
luaT_state
+luaT_temp_luastate
luaT_tolstring
box_txn
box_txn_begin
@@ -148,6 +154,7 @@ box_txn_id
box_key_def_new
box_key_def_delete
box_key_def_dump_parts
+box_key_def_dup
box_key_def_new_ex
box_key_def_merge
box_key_def_validate_key
@@ -174,6 +181,7 @@ box_tuple_update
box_tuple_upsert
box_tuple_extract_key
box_tuple_extract_key_ex
+box_tuple_validate
box_tuple_validate_key_parts
box_tuple_compare
box_tuple_compare_with_key
@@ -223,6 +231,16 @@ box_region_aligned_alloc
box_region_alloc
box_region_truncate
box_region_used
+mp_char2escape
+mp_decode_extl
+mp_ext_hint
+mp_format
+mp_fprint
+mp_parser_hint
+mp_snprint
+mp_type_hint
+mp_vformat
+
# Lua / LuaJIT
@@ -324,6 +342,8 @@ luaopen_ffi
luaL_openlibs
luaL_openlib
luaL_register
+luaL_register_module
+luaL_register_type
luaL_getmetafield
luaL_callmeta
luaL_typerror
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 8/9] module api: add luaL_iscallable with support of cdata metatype
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
` (6 preceding siblings ...)
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 7/9] RFC: module api: extend list of public symbols in 1.10 Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 9/9] module api: luaL_cdata_iscallable Timur Safin
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
From: Alexander Turenko <alexander.turenko@tarantool.org>
Part of #5273.
---
| 1 +
src/lua/utils.c | 43 ++++++++++++++++
src/lua/utils.h | 1 -
test/app-tap/module_api.c | 10 ++++
test/app-tap/module_api.test.lua | 85 +++++++++++++++++++++++++++++++-
5 files changed, 137 insertions(+), 3 deletions(-)
--git a/extra/exports b/extra/exports
index 70b59a0a6..a593375c0 100644
--- a/extra/exports
+++ b/extra/exports
@@ -143,6 +143,7 @@ luaT_release_temp_luastate
luaT_state
luaT_temp_luastate
luaT_tolstring
+luaL_iscallable
box_txn
box_txn_begin
box_txn_commit
diff --git a/src/lua/utils.c b/src/lua/utils.c
index 58c54f8fb..8aa2deb13 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -1057,6 +1057,49 @@ luaL_checkconstchar(struct lua_State *L, int idx, const char **res,
return 0;
}
+/* Based on ffi_meta___call() from luajit/src/lib_ffi.c. */
+static int
+luaL_cdata_iscallable(lua_State *L, int idx)
+{
+ /* Calculate absolute value in the stack. */
+ if (idx < 0)
+ idx = lua_gettop(L) + idx + 1;
+
+ /* Get cdata from the stack. */
+ assert(lua_type(L, idx) == LUA_TCDATA);
+ GCcdata *cd = cdataV(L->base + idx - 1);
+
+ CTState *cts = ctype_cts(L);
+ CTypeID id = cd->ctypeid;
+ CType *ct = ctype_raw(cts, id);
+ if (ctype_isptr(ct->info))
+ id = ctype_cid(ct->info);
+
+ /* Get ctype metamethod. */
+ cTValue *tv = lj_ctype_meta(cts, id, MM_call);
+
+ return tv != NULL;
+}
+
+int
+luaL_iscallable(lua_State *L, int idx)
+{
+ /* Whether it is function. */
+ int res = lua_isfunction(L, idx);
+ if (res == 1)
+ return 1;
+
+ /* Whether it is cdata with metatype with __call field. */
+ if (lua_type(L, idx) == LUA_TCDATA)
+ return luaL_cdata_iscallable(L, idx);
+
+ /* Whether it has metatable with __call field. */
+ res = luaL_getmetafield(L, idx, "__call");
+ if (res == 1)
+ lua_pop(L, 1); /* Pop __call value. */
+ return res;
+}
+
lua_State *
luaT_state(void)
{
diff --git a/src/lua/utils.h b/src/lua/utils.h
index ac6682d80..dca23c299 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -517,7 +517,6 @@ luaT_tolstring(lua_State *L, int idx, size_t *ssize);
LUA_API int
luaL_iscallable(lua_State *L, int idx);
-
/**
* @brief Creates a new Lua coroutine in a protected frame. If
* <lua_newthread> call underneath succeeds, the created Lua state
diff --git a/test/app-tap/module_api.c b/test/app-tap/module_api.c
index 69d22d44b..a79fbed0d 100644
--- a/test/app-tap/module_api.c
+++ b/test/app-tap/module_api.c
@@ -442,6 +442,15 @@ test_tostring(lua_State *L)
return 1;
}
+static int
+test_iscallable(lua_State *L)
+{
+ int exp = lua_toboolean(L, 2);
+ int res = luaL_iscallable(L, 1);
+ lua_pushboolean(L, res == exp);
+ return 1;
+}
+
LUA_API int
luaopen_module_api(lua_State *L)
{
@@ -469,6 +478,7 @@ luaopen_module_api(lua_State *L)
{"test_cpcall", test_cpcall},
{"test_state", test_state},
{"test_tostring", test_tostring},
+ {"iscallable", test_iscallable},
{NULL, NULL}
};
luaL_register(L, "module_api", lib);
diff --git a/test/app-tap/module_api.test.lua b/test/app-tap/module_api.test.lua
index f93257236..a6658cc61 100755
--- a/test/app-tap/module_api.test.lua
+++ b/test/app-tap/module_api.test.lua
@@ -3,7 +3,9 @@
local fio = require('fio')
box.cfg{log = "tarantool.log"}
-build_path = os.getenv("BUILDDIR")
+-- Use BUILDDIR passed from test-run or cwd when run w/o
+-- test-run to find test/app-tap/module_api.{so,dylib}.
+build_path = os.getenv("BUILDDIR") or '.'
package.cpath = fio.pathjoin(build_path, 'test/app-tap/?.so' ) .. ';' ..
fio.pathjoin(build_path, 'test/app-tap/?.dylib') .. ';' ..
package.cpath
@@ -36,8 +38,86 @@ local function test_pushcdata(test, module)
test:is(gc_counter, 1, 'pushcdata gc')
end
+local function test_iscallable(test, module)
+ local ffi = require('ffi')
+
+ ffi.cdef([[
+ struct cdata_1 { int foo; };
+ struct cdata_2 { int foo; };
+ ]])
+
+ local cdata_1 = ffi.new('struct cdata_1')
+ local cdata_1_ref = ffi.new('struct cdata_1 &')
+ local cdata_2 = ffi.new('struct cdata_2')
+ local cdata_2_ref = ffi.new('struct cdata_2 &')
+
+ local nop = function() end
+
+ ffi.metatype('struct cdata_2', {
+ __call = nop,
+ })
+
+ local cases = {
+ {
+ obj = nop,
+ exp = true,
+ description = 'function',
+ },
+ {
+ obj = nil,
+ exp = false,
+ description = 'nil',
+ },
+ {
+ obj = 1,
+ exp = false,
+ description = 'number',
+ },
+ {
+ obj = {},
+ exp = false,
+ description = 'table without metatable',
+ },
+ {
+ obj = setmetatable({}, {}),
+ exp = false,
+ description = 'table without __call metatable field',
+ },
+ {
+ obj = setmetatable({}, {__call = nop}),
+ exp = true,
+ description = 'table with __call metatable field'
+ },
+ {
+ obj = cdata_1,
+ exp = false,
+ description = 'cdata without __call metatable field',
+ },
+ {
+ obj = cdata_1_ref,
+ exp = false,
+ description = 'cdata reference without __call metatable field',
+ },
+ {
+ obj = cdata_2,
+ exp = true,
+ description = 'cdata with __call metatable field',
+ },
+ {
+ obj = cdata_2_ref,
+ exp = true,
+ description = 'cdata reference with __call metatable field',
+ },
+ }
+
+ test:plan(#cases)
+ for _, case in ipairs(cases) do
+ test:ok(module.iscallable(case.obj, case.exp), case.description)
+ end
+end
+
local test = require('tap').test("module_api", function(test)
- test:plan(23)
+ test:plan(24)
local status, module = pcall(require, 'module_api')
test:is(status, true, "module")
test:ok(status, "module is loaded")
@@ -62,6 +142,7 @@ local test = require('tap').test("module_api", function(test)
test:like(msg, 'luaT_error', 'luaT_error')
test:test("pushcdata", test_pushcdata, module)
+ test:test("iscallable", test_iscallable, module)
space:drop()
end)
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [Tarantool-patches] [PATCH 1.10 9/9] module api: luaL_cdata_iscallable
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
` (7 preceding siblings ...)
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 8/9] module api: add luaL_iscallable with support of cdata metatype Timur Safin
@ 2020-09-24 21:00 ` Timur Safin
8 siblings, 0 replies; 11+ messages in thread
From: Timur Safin @ 2020-09-24 21:00 UTC (permalink / raw)
To: v.shpilevoy, alexander.turenko; +Cc: tarantool-patches
In addition to `luaL_iscallable` we need `luaL_cdata_iscallable`
because code which was calling it directly had to be copied to
merger side for 1.10, as there was missing support dislike 2.*
Backported to 1.10
Part of #5273
---
| 1 +
src/lua/utils.c | 2 +-
src/lua/utils.h | 7 +++++++
3 files changed, 9 insertions(+), 1 deletion(-)
--git a/extra/exports b/extra/exports
index a593375c0..e8fddd43c 100644
--- a/extra/exports
+++ b/extra/exports
@@ -119,6 +119,7 @@ coio_getaddrinfo
luaL_pushcdata
luaL_iscdata
luaL_iscallable
+luaL_cdata_iscallable
luaL_checkcdata
luaL_checkconstchar
luaL_checkibuf
diff --git a/src/lua/utils.c b/src/lua/utils.c
index 8aa2deb13..bfc9f2852 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -1058,7 +1058,7 @@ luaL_checkconstchar(struct lua_State *L, int idx, const char **res,
}
/* Based on ffi_meta___call() from luajit/src/lib_ffi.c. */
-static int
+int
luaL_cdata_iscallable(lua_State *L, int idx)
{
/* Calculate absolute value in the stack. */
diff --git a/src/lua/utils.h b/src/lua/utils.h
index dca23c299..136ce64f9 100644
--- a/src/lua/utils.h
+++ b/src/lua/utils.h
@@ -517,6 +517,13 @@ luaT_tolstring(lua_State *L, int idx, size_t *ssize);
LUA_API int
luaL_iscallable(lua_State *L, int idx);
+/**
+ * Check whether a Lua object is a cdata metatype with a __call field.
+ *
+ */
+LUA_API int
+luaL_cdata_iscallable(lua_State *L, int idx);
+
/**
* @brief Creates a new Lua coroutine in a protected frame. If
* <lua_newthread> call underneath succeeds, the created Lua state
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [Tarantool-patches] [PATCH 1.10 7/9] RFC: module api: extend list of public symbols in 1.10
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 7/9] RFC: module api: extend list of public symbols in 1.10 Timur Safin
@ 2020-09-29 6:21 ` Alexander Turenko
0 siblings, 0 replies; 11+ messages in thread
From: Alexander Turenko @ 2020-09-29 6:21 UTC (permalink / raw)
To: Timur Safin; +Cc: tarantool-patches, v.shpilevoy
> diff --git a/extra/exports b/extra/exports
> index a4ac03530..70b59a0a6 100644
> --- a/extra/exports
> +++ b/extra/exports
> @@ -118,7 +118,10 @@ coio_call
> coio_getaddrinfo
> luaL_pushcdata
> luaL_iscdata
> +luaL_iscallable
It should be part of relevant commits (just like on your 2.x branch).
The same for the other functions.
Or you may have one commit for backport (just cherry-pick) and a
separate commit with \public cond + exports.
> +mp_char2escape
> +mp_decode_extl
> +mp_ext_hint
> +mp_format
> +mp_fprint
> +mp_parser_hint
> +mp_snprint
> +mp_type_hint
> +mp_vformat
Those functions are not used in merger. It seems you want to overcome
some linking problem. At least, please, explain this change.
Anyway, including msgpuck headers and using symbols from tarantool looks
dangerous. Maybe we can just expose necessary mp_*() functions into box
api: both to headers and to public symbols, as we usually do?
I looked, the list is not large: mp_next(), mp_check(), mp_store_u32(),
mp_typeof(), mp_check_array(), mp_decode_array(), mp_sizeof_array(),
mp_encode_array() and MP_ARRAY constant.
Alternative: bundle msgpuck into the module, but tweak it to be header
only back (add some ifdefs). This way, I guess, it would be safe to use
external msgpuck and don't bother about symbol names clash (need to
verify, though). At least if mp_next() / mp_check() successfully
traverse over unknown mp_ext (I guess it is so) and you don't need to
parse specific mp_ext types. It'll be enough for most use cases I guess.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2020-09-29 6:21 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-24 21:00 [Tarantool-patches] [PATCH 1.10 0/9] RFC: module api: extend for external merger Lua module Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 1/9] module api: export box_tuple_validate Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 2/9] module api: export box_key_def_dup Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 3/9] module api: luaT_newthread Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 4/9] module api: luaL_register_module & luaL_register_type Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 5/9] module api: luaT_temp_luastate & luaT_release_temp_luastate Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 6/9] module api: luaL_checkibuf & luaL_checkconstchar Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 7/9] RFC: module api: extend list of public symbols in 1.10 Timur Safin
2020-09-29 6:21 ` Alexander Turenko
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 8/9] module api: add luaL_iscallable with support of cdata metatype Timur Safin
2020-09-24 21:00 ` [Tarantool-patches] [PATCH 1.10 9/9] module api: luaL_cdata_iscallable Timur Safin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox