diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/rgw/rgw_lua_utils.h | |
parent | Initial commit. (diff) | |
download | ceph-upstream.tar.xz ceph-upstream.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/rgw/rgw_lua_utils.h')
-rw-r--r-- | src/rgw/rgw_lua_utils.h | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/src/rgw/rgw_lua_utils.h b/src/rgw/rgw_lua_utils.h new file mode 100644 index 000000000..47f7437f3 --- /dev/null +++ b/src/rgw/rgw_lua_utils.h @@ -0,0 +1,199 @@ +#pragma once + +#include <memory> +#include <string> +#include <string_view> +#include <ctime> +#include <lua.hpp> + +#include "include/common_fwd.h" + +namespace rgw::lua { + +// push ceph time in string format: "%Y-%m-%d %H:%M:%S" +template <typename CephTime> +void pushtime(lua_State* L, const CephTime& tp) +{ + const auto tt = CephTime::clock::to_time_t(tp); + const auto tm = *std::localtime(&tt); + char buff[64]; + std::strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm); + lua_pushstring(L, buff); +} + +static inline void pushstring(lua_State* L, std::string_view str) +{ + lua_pushlstring(L, str.data(), str.size()); +} + +static inline void unsetglobal(lua_State* L, const char* name) +{ + lua_pushnil(L); + lua_setglobal(L, name); +} + +// dump the lua stack to stdout +void stack_dump(lua_State* L); + +class lua_state_guard { + lua_State* l; +public: + lua_state_guard(lua_State* _l) : l(_l) {} + ~lua_state_guard() {lua_close(l);} + void reset(lua_State* _l=nullptr) {l = _l;} +}; + +constexpr auto ONE_UPVAL = 1; +constexpr auto TWO_UPVALS = 2; +constexpr auto THREE_UPVALS = 3; +constexpr auto FOUR_UPVALS = 4; +constexpr auto FIVE_UPVALS = 5; + +constexpr auto NO_RETURNVAL = 0; +constexpr auto ONE_RETURNVAL = 1; +constexpr auto TWO_RETURNVALS = 2; +constexpr auto THREE_RETURNVALS = 3; +constexpr auto FOUR_RETURNVALS = 4; +// utility functions to create a metatable +// and tie it to an unnamed table +// +// add an __index method to it, to allow reading values +// if "readonly" parameter is set to "false", it will also add +// a __newindex method to it, to allow writing values +// if the "toplevel" parameter is set to "true", it will name the +// table as well as the metatable, this would allow direct access from +// the lua script. +// +// The MetaTable is expected to be a class with the following members: +// Name (static function returning the unique name of the metatable) +// TableName (static function returning the unique name of the table - needed only for "toplevel" tables) +// Type (typename) - the type of the "upvalue" (the type that the meta table represent) +// IndexClosure (static function return "int" and accept "lua_State*") +// NewIndexClosure (static function return "int" and accept "lua_State*") +// e.g. +// struct MyStructMetaTable { +// static std::string TableName() { +// return "MyStruct"; +// } +// +// using Type = MyStruct; +// +// static int IndexClosure(lua_State* L) { +// const auto value = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(1))); +// ... +// } + +// static int NewIndexClosure(lua_State* L) { +// auto value = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1))); +// ... +// } +// }; +// + +template<typename MetaTable, typename... Upvalues> +void create_metatable(lua_State* L, bool toplevel, Upvalues... upvalues) +{ + constexpr auto upvals_size = sizeof...(upvalues); + const std::array<void*, upvals_size> upvalue_arr = {upvalues...}; + // create table + lua_newtable(L); + if (toplevel) { + // duplicate the table to make sure it remain in the stack + lua_pushvalue(L, -1); + // give table a name (in cae of "toplevel") + lua_setglobal(L, MetaTable::TableName().c_str()); + } + // create metatable + [[maybe_unused]] const auto rc = luaL_newmetatable(L, MetaTable::Name().c_str()); + lua_pushliteral(L, "__index"); + for (const auto upvalue : upvalue_arr) { + lua_pushlightuserdata(L, upvalue); + } + lua_pushcclosure(L, MetaTable::IndexClosure, upvals_size); + lua_rawset(L, -3); + lua_pushliteral(L, "__newindex"); + for (const auto upvalue : upvalue_arr) { + lua_pushlightuserdata(L, upvalue); + } + lua_pushcclosure(L, MetaTable::NewIndexClosure, upvals_size); + lua_rawset(L, -3); + lua_pushliteral(L, "__pairs"); + for (const auto upvalue : upvalue_arr) { + lua_pushlightuserdata(L, upvalue); + } + lua_pushcclosure(L, MetaTable::PairsClosure, upvals_size); + lua_rawset(L, -3); + lua_pushliteral(L, "__len"); + for (const auto upvalue : upvalue_arr) { + lua_pushlightuserdata(L, upvalue); + } + lua_pushcclosure(L, MetaTable::LenClosure, upvals_size); + lua_rawset(L, -3); + // tie metatable and table + lua_setmetatable(L, -2); +} + +template<typename MetaTable> +void create_metatable(lua_State* L, bool toplevel, std::unique_ptr<typename MetaTable::Type>& ptr) +{ + if (ptr) { + create_metatable<MetaTable>(L, toplevel, reinterpret_cast<void*>(ptr.get())); + } else { + lua_pushnil(L); + } +} + +// following struct may be used as a base class for other MetaTable classes +// note, however, this is not mandatory to use it as a base +struct EmptyMetaTable { + // by default everythinmg is "readonly" + // to change, overload this function in the derived + static int NewIndexClosure(lua_State* L) { + throw std::runtime_error("trying to write to readonly field"); + return NO_RETURNVAL; + } + + // by default nothing is iterable + // to change, overload this function in the derived + static int PairsClosure(lua_State* L) { + throw std::runtime_error("trying to iterate over non-iterable field"); + return ONE_RETURNVAL; + } + + // by default nothing is iterable + // to change, overload this function in the derived + static int LenClosure(lua_State* L) { + throw std::runtime_error("trying to get length of non-iterable field"); + return ONE_RETURNVAL; + } + + static void throw_unknown_field(const std::string& index, const std::string& table) { + throw std::runtime_error("unknown field name: " + index + " provided to: " + table); + } +}; + +// create a debug log action +// it expects CephContext to be captured +// it expects one string parameter, which is the message to log +// could be executed from any context that has CephContext +// e.g. +// RGWDebugLog("hello world from lua") +// +void create_debug_action(lua_State* L, CephContext* cct); + +// set the packages search path according to: +// package.path = "<install_dir>/share/lua/5.3/?.lua" │ LuaRocks. +// package.cpath= "<install_dir>/lib/lua/5.3/?.so" +void set_package_path(lua_State* L, const std::string& install_dir); + +// open standard lua libs and remove the following functions: +// os.exit() +// load() +// loadfile() +// loadstring() +// dofile() +// and the "debug" library +void open_standard_libs(lua_State* L); + +} + |