effil/src/cpp/lua-module.cpp
2020-02-29 11:19:17 +03:00

134 lines
4.3 KiB
C++

#include "threading.h"
#include "shared-table.h"
#include "garbage-collector.h"
#include "channel.h"
#include <lua.hpp>
using namespace effil;
namespace {
sol::object createTable(sol::this_state lua, const sol::optional<sol::object>& tbl) {
if (tbl)
{
REQUIRE(tbl->get_type() == sol::type::table) << "Unexpected type for effil.table, table expected got: "
<< lua_typename(lua, (int)tbl->get_type());
return createStoredObject(*tbl)->unpack(lua);
}
return sol::make_object(lua, GC::instance().create<SharedTable>());
}
sol::object createChannel(const sol::stack_object& capacity, sol::this_state lua) {
return sol::make_object(lua, GC::instance().create<Channel>(capacity));
}
SharedTable globalTable = GC::instance().create<SharedTable>();
std::string getLuaTypename(const sol::stack_object& obj) {
return luaTypename<>(obj);
}
size_t luaSize(const sol::stack_object& obj) {
if (obj.is<SharedTable>())
return SharedTable::luaSize(obj);
else if (obj.is<Channel>())
return obj.as<Channel>().size();
throw effil::Exception() << "Unsupported type "
<< luaTypename(obj) << " for effil.size()";
}
sol::object luaDump(sol::this_state lua, const sol::stack_object& obj) {
if (obj.is<SharedTable>()) {
BaseHolder::DumpCache cache;
return obj.as<SharedTable>().luaDump(lua, cache);
}
else if (obj.get_type() == sol::type::table) {
return obj;
}
throw effil::Exception() << "bad argument #1 to 'effil.dump' (table expected, got "
<< luaTypename(obj) << ")";
}
sol::table luaThreadConfig(sol::this_state state, const sol::stack_object& obj) {
REQUIRE(obj.valid() && obj.get_type() == sol::type::function)
<< "bad argument #1 to 'effil.thread' (function expected, got "
<< luaTypename(obj) << ")";
auto lua = sol::state_view(state);
const sol::function func = obj.as<sol::function>();
auto config = lua.create_table_with(
"path", lua["package"]["path"],
"cpath", lua["package"]["cpath"],
"step", 200
);
auto meta = lua.create_table_with();
meta[sol::meta_function::call] = [func](sol::this_state lua,
const sol::stack_table& self, const sol::variadic_args& args)
{
return sol::make_object(lua, GC::instance().create<Thread>(
self["path"], self["cpath"], self["step"], func, args));
};
config[sol::metatable_key] = meta;
return config;
}
} // namespace
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
int luaopen_effil(lua_State* L) {
sol::state_view lua(L);
Thread::exportAPI(lua);
SharedTable::exportAPI(lua);
Channel::exportAPI(lua);
const sol::table gcApi = GC::exportAPI(lua);
const sol::object gLuaTable = sol::make_object(lua, globalTable);
const auto luaIndex = [gcApi, gLuaTable](
const sol::stack_object& obj, const std::string& key) -> sol::object
{
if (key == "G")
return gLuaTable;
else if (key == "gc")
return gcApi;
else if (key == "version")
return sol::make_object(obj.lua_state(), "0.1.0");
return sol::nil;
};
sol::usertype<EffilApiMarker> type("new", sol::no_constructor,
"thread", luaThreadConfig,
"thread_id", threadId,
"sleep", sleep,
"yield", yield,
"table", createTable,
"rawset", SharedTable::luaRawSet,
"rawget", SharedTable::luaRawGet,
"setmetatable", SharedTable::luaSetMetatable,
"getmetatable", SharedTable::luaGetMetatable,
"channel", createChannel,
"type", getLuaTypename,
"pairs", SharedTable::globalLuaPairs,
"ipairs", SharedTable::globalLuaIPairs,
"next", SharedTable::globalLuaNext,
"size", luaSize,
"dump", luaDump,
"hardware_threads", std::thread::hardware_concurrency,
sol::meta_function::index, luaIndex
);
sol::stack::push(lua, type);
sol::stack::pop<sol::object>(lua);
sol::stack::push(lua, EffilApiMarker());
return 1;
}