diff --git a/src/cpp/lua-helpers.cpp b/src/cpp/lua-helpers.cpp index 4a95696..e1fa9f5 100644 --- a/src/cpp/lua-helpers.cpp +++ b/src/cpp/lua-helpers.cpp @@ -2,6 +2,51 @@ namespace effil { +namespace +{ + +std::string luaError(int errCode) +{ + switch(errCode) + { + case LUA_ERRSYNTAX: return "Invalid syntax (LUA_ERRSYNTAX)"; + case LUA_ERRMEM: return "Memory allocation error (LUA_ERRMEM)"; + case LUA_ERRRUN: return "Execution error (LUA_ERRRUN)"; + case LUA_ERRGCMM: return "Error in __gc method (LUA_ERRGCMM)"; + case LUA_ERRERR: return "Recursive error (LUA_ERRERR)"; + default: return "Unknown"; + } +} + +int dumpMemoryWriter(lua_State*, const void* batch, size_t batchSize, void* storage) { + if (storage == nullptr || batch == nullptr) + return 1; + if (batchSize) { + std::string& buff = *reinterpret_cast(storage); + const char* newData = reinterpret_cast(batch); + buff.insert(buff.end(), newData, newData + batchSize); + } + return 0; +} + +} + +std::string dumpFunction(const sol::function& f) { + sol::state_view lua(f.lua_state()); + sol::stack::push(lua, f); + std::string result; + int ret = lua_dump(lua, dumpMemoryWriter, &result); + REQUIRE(ret == LUA_OK) << "Unable to dump Lua function: " << luaError(ret); + sol::stack::remove(lua, -1, 1); + return result; +} + +sol::function loadString(const sol::state_view& lua, const std::string& str) { + int ret = luaL_loadbuffer(lua, str.c_str(), str.size(), nullptr); + REQUIRE(ret == LUA_OK) << "Unable to load function from string: " << luaError(ret); + return sol::stack::pop(lua); +} + std::chrono::milliseconds fromLuaTime(int duration, const sol::optional& period) { using namespace std::chrono; diff --git a/src/cpp/lua-helpers.h b/src/cpp/lua-helpers.h index 2862849..bceedeb 100644 --- a/src/cpp/lua-helpers.h +++ b/src/cpp/lua-helpers.h @@ -6,27 +6,8 @@ namespace effil { -// TODO: make function more reliable -// string.dump can be changed by user -// TODO: Add cache for each state -inline std::string dumpFunction(const sol::function& f) { - sol::state_view lua(f.lua_state()); - sol::function dumper = lua["string"]["dump"]; - REQUIRE(dumper.valid() && dumper.get_type() == sol::type::function) - << "Invalid string.dump() in state"; - return dumper(f); -} - -// TODO: make function more reliable -// loadstring can be changed by user -// TODO: Add cache for each state -inline sol::function loadString(const sol::state_view& lua, const std::string& str) { - sol::function loader = lua["loadstring"]; - REQUIRE(loader.valid() && loader.get_type() == sol::type::function) - << "Invalid loadstring function"; - return loader(str); -} - +std::string dumpFunction(const sol::function& f); +sol::function loadString(const sol::state_view& lua, const std::string& str); std::chrono::milliseconds fromLuaTime(int duration, const sol::optional& period); typedef std::vector StoredArray; diff --git a/src/cpp/stored-object.cpp b/src/cpp/stored-object.cpp index 387cbbf..7a8c675 100644 --- a/src/cpp/stored-object.cpp +++ b/src/cpp/stored-object.cpp @@ -50,10 +50,7 @@ public: template FunctionHolder(SolObject luaObject) noexcept { sol::state_view lua(luaObject.lua_state()); - sol::function dumper = lua["string"]["dump"]; - if (!dumper.valid()) - throw Exception() << "Invalid string.dump()"; - function_ = dumper(luaObject); + function_ = dumpFunction(luaObject); } bool rawCompare(const BaseHolder* other) const noexcept final { @@ -61,10 +58,7 @@ public: } sol::object unpack(sol::this_state state) const final { - sol::state_view lua((lua_State*)state); - sol::function loader = lua["loadstring"]; - REQUIRE(loader.valid()) << "Invalid loadstring()"; - sol::function result = loader(function_); + sol::function result = loadString(state, function_); // The result of restaring always is valid function. assert(result.valid()); return sol::make_object(state, result);