Tarantool development patches archive
 help / color / mirror / Atom feed
* [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
---
 extra/exports | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

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
 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.
---
 extra/exports                    |  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(-)

diff --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
---
 extra/exports   | 1 +
 src/lua/utils.c | 2 +-
 src/lua/utils.h | 7 +++++++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --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