Function dumping using C API (#49)

This commit is contained in:
mihacooper 2017-06-11 17:13:48 +03:00 committed by Ilia
parent 7947d7af17
commit 265b12370b
3 changed files with 49 additions and 29 deletions

View File

@ -2,6 +2,51 @@
namespace effil { 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<std::string*>(storage);
const char* newData = reinterpret_cast<const char*>(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<sol::function>(lua);
}
std::chrono::milliseconds fromLuaTime(int duration, const sol::optional<std::string>& period) { std::chrono::milliseconds fromLuaTime(int duration, const sol::optional<std::string>& period) {
using namespace std::chrono; using namespace std::chrono;

View File

@ -6,27 +6,8 @@
namespace effil { namespace effil {
// TODO: make function more reliable std::string dumpFunction(const sol::function& f);
// string.dump can be changed by user sol::function loadString(const sol::state_view& lua, const std::string& str);
// 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::chrono::milliseconds fromLuaTime(int duration, const sol::optional<std::string>& period); std::chrono::milliseconds fromLuaTime(int duration, const sol::optional<std::string>& period);
typedef std::vector<effil::StoredObject> StoredArray; typedef std::vector<effil::StoredObject> StoredArray;

View File

@ -50,10 +50,7 @@ public:
template <typename SolObject> template <typename SolObject>
FunctionHolder(SolObject luaObject) noexcept { FunctionHolder(SolObject luaObject) noexcept {
sol::state_view lua(luaObject.lua_state()); sol::state_view lua(luaObject.lua_state());
sol::function dumper = lua["string"]["dump"]; function_ = dumpFunction(luaObject);
if (!dumper.valid())
throw Exception() << "Invalid string.dump()";
function_ = dumper(luaObject);
} }
bool rawCompare(const BaseHolder* other) const noexcept final { bool rawCompare(const BaseHolder* other) const noexcept final {
@ -61,10 +58,7 @@ public:
} }
sol::object unpack(sol::this_state state) const final { sol::object unpack(sol::this_state state) const final {
sol::state_view lua((lua_State*)state); sol::function result = loadString(state, function_);
sol::function loader = lua["loadstring"];
REQUIRE(loader.valid()) << "Invalid loadstring()";
sol::function result = loader(function_);
// The result of restaring always is valid function. // The result of restaring always is valid function.
assert(result.valid()); assert(result.valid());
return sol::make_object(state, result); return sol::make_object(state, result);