]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_lua_utils.h
import quincy beta 17.1.0
[ceph.git] / ceph / src / rgw / rgw_lua_utils.h
CommitLineData
f67539c2
TL
1#pragma once
2
3#include <memory>
4#include <string>
5#include <string_view>
6#include <ctime>
7#include <lua.hpp>
8
9#include "include/common_fwd.h"
10
11namespace rgw::lua {
12
13// push ceph time in string format: "%Y-%m-%d %H:%M:%S"
14template <typename CephTime>
15void pushtime(lua_State* L, const CephTime& tp)
16{
17 const auto tt = CephTime::clock::to_time_t(tp);
18 const auto tm = *std::localtime(&tt);
19 char buff[64];
20 std::strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm);
21 lua_pushstring(L, buff);
22}
23
24static inline void pushstring(lua_State* L, std::string_view str)
25{
26 lua_pushlstring(L, str.data(), str.size());
27}
28
29static inline void unsetglobal(lua_State* L, const char* name)
30{
31 lua_pushnil(L);
32 lua_setglobal(L, name);
33}
34
35// dump the lua stack to stdout
36void stack_dump(lua_State* L);
37
38class lua_state_guard {
39 lua_State* l;
40public:
41 lua_state_guard(lua_State* _l) : l(_l) {}
42 ~lua_state_guard() {lua_close(l);}
43 void reset(lua_State* _l=nullptr) {l = _l;}
44};
45
46constexpr auto ONE_UPVAL = 1;
47constexpr auto TWO_UPVALS = 2;
48constexpr auto THREE_UPVALS = 3;
49constexpr auto FOUR_UPVALS = 4;
50constexpr auto FIVE_UPVALS = 5;
51
52constexpr auto NO_RETURNVAL = 0;
53constexpr auto ONE_RETURNVAL = 1;
54constexpr auto TWO_RETURNVALS = 2;
55constexpr auto THREE_RETURNVALS = 3;
56constexpr auto FOUR_RETURNVALS = 4;
57// utility functions to create a metatable
58// and tie it to an unnamed table
59//
60// add an __index method to it, to allow reading values
61// if "readonly" parameter is set to "false", it will also add
62// a __newindex method to it, to allow writing values
63// if the "toplevel" parameter is set to "true", it will name the
64// table as well as the metatable, this would allow direct access from
65// the lua script.
66//
67// The MetaTable is expected to be a class with the following members:
68// Name (static function returning the unique name of the metatable)
69// TableName (static function returning the unique name of the table - needed only for "toplevel" tables)
70// Type (typename) - the type of the "upvalue" (the type that the meta table represent)
71// IndexClosure (static function return "int" and accept "lua_State*")
72// NewIndexClosure (static function return "int" and accept "lua_State*")
73// e.g.
74// struct MyStructMetaTable {
75// static std::string TableName() {
76// return "MyStruct";
77// }
78//
79// using Type = MyStruct;
80//
81// static int IndexClosure(lua_State* L) {
82// const auto value = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(1)));
83// ...
84// }
85
86// static int NewIndexClosure(lua_State* L) {
87// auto value = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
88// ...
89// }
90// };
91//
92
93template<typename MetaTable, typename... Upvalues>
94void create_metatable(lua_State* L, bool toplevel, Upvalues... upvalues)
95{
96 constexpr auto upvals_size = sizeof...(upvalues);
97 const std::array<void*, upvals_size> upvalue_arr = {upvalues...};
98 // create table
99 lua_newtable(L);
100 if (toplevel) {
101 // duplicate the table to make sure it remain in the stack
102 lua_pushvalue(L, -1);
103 // give table a name (in cae of "toplevel")
104 lua_setglobal(L, MetaTable::TableName().c_str());
105 }
106 // create metatable
107 [[maybe_unused]] const auto rc = luaL_newmetatable(L, MetaTable::Name().c_str());
108 lua_pushliteral(L, "__index");
109 for (const auto upvalue : upvalue_arr) {
110 lua_pushlightuserdata(L, upvalue);
111 }
112 lua_pushcclosure(L, MetaTable::IndexClosure, upvals_size);
113 lua_rawset(L, -3);
114 lua_pushliteral(L, "__newindex");
115 for (const auto upvalue : upvalue_arr) {
116 lua_pushlightuserdata(L, upvalue);
117 }
118 lua_pushcclosure(L, MetaTable::NewIndexClosure, upvals_size);
119 lua_rawset(L, -3);
120 lua_pushliteral(L, "__pairs");
121 for (const auto upvalue : upvalue_arr) {
122 lua_pushlightuserdata(L, upvalue);
123 }
124 lua_pushcclosure(L, MetaTable::PairsClosure, upvals_size);
125 lua_rawset(L, -3);
126 lua_pushliteral(L, "__len");
127 for (const auto upvalue : upvalue_arr) {
128 lua_pushlightuserdata(L, upvalue);
129 }
130 lua_pushcclosure(L, MetaTable::LenClosure, upvals_size);
131 lua_rawset(L, -3);
132 // tie metatable and table
133 lua_setmetatable(L, -2);
134}
135
136template<typename MetaTable>
137void create_metatable(lua_State* L, bool toplevel, std::unique_ptr<typename MetaTable::Type>& ptr)
138{
139 if (ptr) {
140 create_metatable<MetaTable>(L, toplevel, reinterpret_cast<void*>(ptr.get()));
141 } else {
142 lua_pushnil(L);
143 }
144}
145
146// following struct may be used as a base class for other MetaTable classes
147// note, however, this is not mandatory to use it as a base
148struct EmptyMetaTable {
149 // by default everythinmg is "readonly"
150 // to change, overload this function in the derived
151 static int NewIndexClosure(lua_State* L) {
20effc67 152 return luaL_error(L, "trying to write to readonly field");
f67539c2
TL
153 }
154
155 // by default nothing is iterable
156 // to change, overload this function in the derived
157 static int PairsClosure(lua_State* L) {
20effc67 158 return luaL_error(L, "trying to iterate over non-iterable field");
f67539c2
TL
159 }
160
161 // by default nothing is iterable
162 // to change, overload this function in the derived
163 static int LenClosure(lua_State* L) {
20effc67 164 return luaL_error(L, "trying to get length of non-iterable field");
f67539c2
TL
165 }
166
20effc67
TL
167 static int error_unknown_field(lua_State* L, const std::string& index, const std::string& table) {
168 return luaL_error(L, "unknown field name: %s provided to: %s",
169 index.c_str(), table.c_str());
f67539c2
TL
170 }
171};
172
173// create a debug log action
174// it expects CephContext to be captured
175// it expects one string parameter, which is the message to log
176// could be executed from any context that has CephContext
177// e.g.
178// RGWDebugLog("hello world from lua")
179//
180void create_debug_action(lua_State* L, CephContext* cct);
181
182// set the packages search path according to:
183// package.path = "<install_dir>/share/lua/5.3/?.lua" │ LuaRocks.
184// package.cpath= "<install_dir>/lib/lua/5.3/?.so"
185void set_package_path(lua_State* L, const std::string& install_dir);
186
187// open standard lua libs and remove the following functions:
188// os.exit()
189// load()
190// loadfile()
191// loadstring()
192// dofile()
193// and the "debug" library
194void open_standard_libs(lua_State* L);
195
196}
197