Get rid of effil.lua and allow to capture api in upvalue (#107)

This commit is contained in:
mihacooper 2018-10-10 19:39:07 +03:00 committed by Ilia
parent 8954dbe115
commit d189d67349
7 changed files with 106 additions and 101 deletions

View File

@ -44,12 +44,12 @@ add_library(effil SHARED ${SOURCES})
target_link_libraries(effil ${LUA_LIBRARY})
if (WIN32)
set_target_properties(effil PROPERTIES
PREFIX lib
PREFIX ""
SUFFIX .dll)
else()
target_link_libraries(effil -lpthread -ldl)
set_target_properties(effil PROPERTIES
PREFIX lib
PREFIX ""
SUFFIX .so)
endif()
@ -66,10 +66,6 @@ endif()
#----------
# INSTALL -
#----------
install(FILES src/lua/effil.lua
DESTINATION ${CMAKE_INSTALL_PREFIX}
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)
install(TARGETS effil
DESTINATION ${CMAKE_INSTALL_PREFIX}
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ)

View File

@ -9,15 +9,6 @@ using namespace effil;
namespace {
sol::object createThread(const sol::this_state& lua,
const std::string& path,
const std::string& cpath,
int step,
const sol::function& function,
const sol::variadic_args& args) {
return sol::make_object(lua, GC::instance().create<Thread>(path, cpath, step, function, args));
}
sol::object createTable(sol::this_state lua, const sol::optional<sol::object>& tbl) {
if (tbl)
{
@ -34,41 +25,94 @@ sol::object createChannel(const sol::stack_object& capacity, sol::this_state lua
SharedTable globalTable = GC::instance().create<SharedTable>();
std::string getLuaTypename(const sol::stack_object& obj)
{
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::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_libeffil(lua_State* L) {
int luaopen_effil(lua_State* L) {
sol::state_view lua(L);
Thread::exportAPI(lua);
SharedTable::exportAPI(lua);
Channel::exportAPI(lua);
sol::table publicApi = lua.create_table_with(
"thread", createThread,
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,
"table_size", SharedTable::luaSize,
"setmetatable", SharedTable::luaSetMetatable,
"getmetatable", SharedTable::luaGetMetatable,
"G", sol::make_object(lua, globalTable),
"gc", GC::exportAPI(lua),
"channel", createChannel,
"type", getLuaTypename,
"pairs", SharedTable::globalLuaPairs,
"ipairs", SharedTable::globalLuaIPairs,
"allow_table_upvalues", luaAllowTableUpvalues
"size", luaSize,
"allow_table_upvalues", luaAllowTableUpvalues,
sol::meta_function::index, luaIndex
);
sol::stack::push(lua, publicApi);
sol::stack::push(lua, type);
sol::stack::pop<sol::object>(lua);
sol::stack::push(lua, EffilApiMarker());
return 1;
}

View File

@ -15,6 +15,15 @@ namespace effil {
namespace {
class ApiReferenceHolder : public BaseHolder {
public:
bool rawCompare(const BaseHolder*) const noexcept final { return true; }
sol::object unpack(sol::this_state lua) const final {
luaopen_effil(lua);
return sol::stack::pop<sol::object>(lua);
}
};
class NilHolder : public BaseHolder {
public:
bool rawCompare(const BaseHolder*) const noexcept final { return true; }
@ -163,6 +172,8 @@ StoredObject fromSolObject(const SolObject& luaObject) {
return std::make_unique<FunctionHolder>(luaObject);
else if (luaObject.template is<Thread>())
return std::make_unique<GCObjectHolder<Thread>>(luaObject);
else if (luaObject.template is<EffilApiMarker>())
return std::make_unique<ApiReferenceHolder>();
else
throw Exception() << "Unable to store userdata object";
case sol::type::function: {

View File

@ -7,6 +7,8 @@
namespace effil {
struct EffilApiMarker{};
// Represents an interface for lua type stored at C++ code
class BaseHolder {
public:

View File

@ -16,6 +16,12 @@
# define LUA_INDEX_TYPE lua_Number
#endif
extern "C"
#ifdef _WIN32
__declspec(dllexport)
#endif
int luaopen_effil(lua_State* L);
namespace effil {
class Exception : public sol::error {

View File

@ -1,56 +0,0 @@
local capi = require 'libeffil'
local api = {
version = "0.1.0",
table = capi.table,
thread_id = capi.thread_id,
sleep = capi.sleep,
yield = capi.yield,
rawget = capi.rawget,
rawset = capi.rawset,
setmetatable = capi.setmetatable,
getmetatable = capi.getmetatable,
G = capi.G,
gc = capi.gc,
channel = capi.channel,
type = capi.type,
pairs = capi.pairs,
ipairs = capi.ipairs,
allow_table_upvalues = capi.allow_table_upvalues
}
api.size = function (something)
local t = api.type(something)
if t == "effil.table" then
return capi.table_size(something)
elseif t == "effil.channel" then
return something:size()
else
error("Unsupported type " .. t .. " for effil.size()")
end
end
local function run_thread(config, f, ...)
return capi.thread(config.path, config.cpath, config.step, f, ...)
end
-- Creates thread runner with given function
-- configurable parameters:
-- path - lua modules search path in child thread
-- cpath - lua libs search path in child thread
-- step - who fast reacte on state changing
-- __call - run thread, can be invoked multiple times
api.thread = function (f)
if type(f) ~= "function" then
error("bad argument #1 to 'effil.thread' (function expected, got " .. capi.type(f) .. ")")
end
local thread_config = {
path = package.path,
cpath = package.cpath,
step = 200 }
setmetatable(thread_config, {__call = function(c, ...) return run_thread(c, f, ...) end})
return thread_config
end
return api

View File

@ -1,5 +1,7 @@
require "bootstrap-tests"
local effil = effil
test.thread.tear_down = default_tear_down
test.thread.wait = function ()
@ -26,7 +28,7 @@ end
test.thread.timed_get = function ()
local thread = effil.thread(function()
require('effil').sleep(2)
effil.sleep(2)
return "-_-"
end)()
test.is_nil(thread:get(1))
@ -35,7 +37,7 @@ end
test.thread.timed_get = function ()
local thread = effil.thread(function()
require('effil').sleep(2)
effil.sleep(2)
return 8
end)()
@ -50,7 +52,7 @@ end
test.thread.async_wait = function()
local thread = effil.thread( function()
require('effil').sleep(1)
effil.sleep(1)
end)()
local iter = 0
@ -86,7 +88,7 @@ test.thread.cancel = function ()
jit ~= nil and
function()
while true do
require("effil").yield()
effil.yield()
end
end
or
@ -218,7 +220,7 @@ end
test.thread.timed_cancel = function ()
local thread = effil.thread(function()
require("effil").sleep(4)
effil.sleep(4)
end)()
test.is_false(thread:cancel(100, "ms"))
thread:wait()
@ -283,7 +285,7 @@ test.this_thread.functions = function ()
local thread_factory = effil.thread(
function(share)
share["child.id"] = require('effil').thread_id()
share["child.id"] = effil.thread_id()
end
)
local thread = thread_factory(share)
@ -297,12 +299,12 @@ end
test.this_thread.cancel_with_yield = function ()
local share = effil.table()
local spec = effil.thread(function (share)
require('effil').sleep(1)
effil.sleep(1)
for i=1,10000 do
-- Just waiting
end
share.done = true
require("effil").yield()
effil.yield()
share.afet_yield = true
end)
spec.step = 0
@ -318,7 +320,7 @@ test.this_thread.pause_with_yield = function ()
local share = effil.table({stop = false})
local spec = effil.thread(function (share)
while not share.stop do
require("effil").yield()
effil.yield()
end
share.done = true
return true
@ -339,7 +341,7 @@ test.this_thread.pause_with_yield = function ()
end
local function worker(cmd)
eff = require("effil")
eff = effil
while not cmd.need_to_stop do
eff.yield()
end