Coverage Report

Created: 2024-04-24 06:23

/src/tarantool/src/box/lua/func_adapter.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SPDX-License-Identifier: BSD-2-Clause
3
 *
4
 * Copyright 2010-2023, Tarantool AUTHORS, please see AUTHORS file.
5
 */
6
#include "box/lua/func_adapter.h"
7
#include "box/lua/tuple.h"
8
#include "box/tuple.h"
9
#include "core/func_adapter.h"
10
#include "lua/msgpack.h"
11
#include "lua/utils.h"
12
13
#include "box/port.h"
14
15
/**
16
 * Specialization of func_adapter for Lua functions and other callable objects.
17
 */
18
struct func_adapter_lua {
19
  /**
20
   * Virtual table.
21
   */
22
  const struct func_adapter_vtab *vtab;
23
  /**
24
   * Reference to the function in Lua registry.
25
   */
26
  int func_ref;
27
};
28
29
/**
30
 * Call the function with ports.
31
 */
32
static int
33
func_adapter_lua_call(struct func_adapter *func, struct port *args, struct port *ret)
34
0
{
35
0
  struct func_adapter_lua *lua_func =
36
0
    (struct func_adapter_lua *)func;
37
0
  int coro_ref = LUA_REFNIL;
38
0
  struct lua_State *L = fiber_lua_state(fiber());
39
  /*
40
   * Do not use Lua stack from fiber storage if it is used by args
41
   * because port_lua is not allowed to be dumped on the same Lua stack.
42
   */
43
0
  if (args != NULL && port_is_lua(args)) {
44
0
    struct port_lua *args_lua = (struct port_lua *)args;
45
0
    struct lua_State *args_L = args_lua->L;
46
0
    if (args_L == L)
47
0
      L = NULL;
48
0
  }
49
0
  if (L == NULL) {
50
0
    L = luaT_newthread(tarantool_L);
51
0
    if (L == NULL)
52
0
      panic("Cannot create Lua thread");
53
0
    coro_ref = luaL_ref(tarantool_L, LUA_REGISTRYINDEX);
54
0
  }
55
0
  int top_svp = lua_gettop(L);
56
57
0
  lua_rawgeti(L, LUA_REGISTRYINDEX, lua_func->func_ref);
58
0
  if (args != NULL)
59
0
    port_dump_lua(args, L, PORT_DUMP_LUA_MODE_FLAT);
60
61
0
  int nargs = lua_gettop(L) - top_svp - 1;
62
0
  bool ok = luaT_call(L, nargs, LUA_MULTRET) == 0;
63
64
0
  if (!ok || ret == NULL) {
65
0
    luaL_unref(tarantool_L, LUA_REGISTRYINDEX, coro_ref);
66
0
  } else {
67
0
    port_lua_create_at(ret, L, top_svp + 1);
68
0
    struct port_lua *port_lua = (struct port_lua *)ret;
69
0
    port_lua->ref = coro_ref;
70
0
  }
71
0
  return ok ? 0 : -1;
72
0
}
73
74
/**
75
 * Virtual destructor.
76
 */
77
static void
78
func_adapter_lua_destroy(struct func_adapter *func_base)
79
0
{
80
0
  struct func_adapter_lua *func = (struct func_adapter_lua *)func_base;
81
0
  luaL_unref(tarantool_L, LUA_REGISTRYINDEX, func->func_ref);
82
0
  free(func);
83
0
}
84
85
bool
86
func_adapter_is_lua(struct func_adapter *func)
87
0
{
88
0
  assert(func != NULL);
89
0
  return func->vtab->destroy == func_adapter_lua_destroy;
90
0
}
91
92
void
93
func_adapter_lua_get_func(struct func_adapter *func, lua_State *L)
94
0
{
95
0
  assert(func != NULL);
96
0
  assert(func->vtab->destroy == func_adapter_lua_destroy);
97
0
  struct func_adapter_lua *lua_func =
98
0
    (struct func_adapter_lua *)func;
99
0
  lua_rawgeti(L, LUA_REGISTRYINDEX, lua_func->func_ref);
100
0
}
101
102
struct func_adapter *
103
func_adapter_lua_create(lua_State *L, int idx)
104
0
{
105
0
  static const struct func_adapter_vtab vtab = {
106
0
    .call = func_adapter_lua_call,
107
0
    .destroy = func_adapter_lua_destroy,
108
0
  };
109
0
  struct func_adapter_lua *func = xmalloc(sizeof(*func));
110
0
  assert(luaL_iscallable(L, idx));
111
0
  lua_pushvalue(L, idx);
112
0
  func->func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
113
0
  func->vtab = &vtab;
114
0
  return (struct func_adapter *)func;
115
0
}