parent
2333863a68
commit
925494e7d5
@ -209,6 +209,8 @@ Thread result: 3
|
||||
Effil allows to transmit data between threads (Lua interpreter states) using `effil.channel`, `effil.table` or directly as parameters of `effil.thread`.
|
||||
- Primitive types are transmitted 'as is' by copy: `nil`, `boolean`, `number`, `string`
|
||||
- Functions are dumped using [`lua_dump`](#https://www.lua.org/manual/5.3/manual.html#lua_dump). Upvalues are captured according to [the rules](#functions-upvalues).
|
||||
- C functions (for which `lua_iscfunction` returns true) are transmitted just by a pointer using `lua_tocfunction` (in original lua_State) and lua_pushcfunction (in new lua_State).
|
||||
**caution**: in LuaJIT standard functions like tonumber are not real C function, so `lua_iscfunction` returns true but `lua_tocfunction` returns nullptr. Due to that we don't find way to transmit it between lua_States.
|
||||
- **Userdata and Lua threads (coroutines)** are not supported.
|
||||
- Tables are serialized to `effil.table` recursively. So, any Lua table becomes `effil.table`. Table serialization may take a lot of time for big table. Thus, it's better to put data directly to `effil.table` avoiding a table serialization. Let's consider 2 examples:
|
||||
```Lua
|
||||
|
||||
@ -108,7 +108,6 @@ class FunctionHolder : public GCObjectHolder<Function> {
|
||||
public:
|
||||
template <typename SolType>
|
||||
FunctionHolder(const SolType& luaObject) : GCObjectHolder<Function>(luaObject) {}
|
||||
FunctionHolder(GCHandle handle) : GCObjectHolder(handle) {}
|
||||
|
||||
sol::object unpack(sol::this_state state) const final {
|
||||
return GC::instance().get<Function>(handle_).loadFunction(state);
|
||||
@ -119,6 +118,29 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CFunctionHolder : public BaseHolder {
|
||||
public:
|
||||
CFunctionHolder(sol::state_view state, int stack_index)
|
||||
: BaseHolder()
|
||||
{
|
||||
cfunction_ = lua_tocfunction(state, stack_index);
|
||||
REQUIRE(cfunction_ != nullptr) << "can't get C function pointer";
|
||||
}
|
||||
|
||||
sol::object unpack(sol::this_state state) const final {
|
||||
lua_pushcfunction(state, cfunction_);
|
||||
return sol::stack::pop<sol::object>(state);
|
||||
}
|
||||
|
||||
bool rawCompare(const BaseHolder* other) const override {
|
||||
const auto cfh = dynamic_cast<const CFunctionHolder*>(other);
|
||||
return cfh && cfh->cfunction_ == cfunction_;
|
||||
}
|
||||
|
||||
private:
|
||||
lua_CFunction cfunction_;
|
||||
};
|
||||
|
||||
void dumpTable(SharedTable& target, const sol::table& luaTable, SolTableToShared& visited);
|
||||
|
||||
StoredObject makeStoredObject(const sol::object& luaObject, SolTableToShared& visited) {
|
||||
@ -186,6 +208,11 @@ StoredObject fromSolObject(const SolObject& luaObject, SolTableToShared& visited
|
||||
else
|
||||
throw Exception() << "Unable to store userdata object";
|
||||
case sol::type::function: {
|
||||
{
|
||||
auto poper = sol::stack::push_pop(luaObject);
|
||||
if (lua_iscfunction(luaObject.lua_state(), -1))
|
||||
return std::make_unique<CFunctionHolder>(luaObject.lua_state(), -1);
|
||||
}
|
||||
Function func = GC::instance().create<Function>(luaObject, visited);
|
||||
return std::make_unique<FunctionHolder>(func.handle());
|
||||
}
|
||||
|
||||
43
tests/lua/function.lua
Normal file
43
tests/lua/function.lua
Normal file
@ -0,0 +1,43 @@
|
||||
require "bootstrap-tests"
|
||||
|
||||
test.func.tear_down = default_tear_down
|
||||
|
||||
test.func.check_truly_c_functions_p = function(func)
|
||||
test.equal(type(func), "function")
|
||||
|
||||
local t = effil.table()
|
||||
local ret, _ = pcall(function() t["func"] = func end)
|
||||
test.equal(ret, true)
|
||||
end
|
||||
|
||||
test.func.check_truly_c_functions_p(coroutine.create)
|
||||
test.func.check_truly_c_functions_p(effil.size)
|
||||
|
||||
test.func.check_tosting_c_functions = function()
|
||||
local t = effil.table()
|
||||
|
||||
if jit then
|
||||
-- in LuaJIT it's not real C function
|
||||
local ret, msg = pcall(function() t["tostring"] = tostring end)
|
||||
test.equal(ret, false)
|
||||
test.equal(msg, "effil.table: can't get C function pointer")
|
||||
else
|
||||
t["tostring"] = tostring
|
||||
|
||||
if LUA_VERSION > 51 then
|
||||
test.equal(t["tostring"], tostring)
|
||||
else
|
||||
test.not_equal(t["tostring"], tostring)
|
||||
end -- LUA_VERSION > 51
|
||||
|
||||
test.equal(t["tostring"](123), tostring(123))
|
||||
test.equal(effil.thread(function() return t["tostring"](123) end)():get(), tostring(123))
|
||||
|
||||
local foo = tostring
|
||||
test.equal(foo, tostring)
|
||||
test.equal(foo(123), tostring(123))
|
||||
test.equal(effil.thread(function() return foo(123) end)():get(), tostring(123))
|
||||
end -- jit
|
||||
end
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
#!/usr/bin/env lua
|
||||
|
||||
if jit then
|
||||
print("Using LuaJIT")
|
||||
else
|
||||
print("Using " .. _VERSION)
|
||||
end
|
||||
|
||||
local scripts_path = arg[0]:gsub("[\\/]run_tests", "")
|
||||
local src_path = scripts_path .. "/../.."
|
||||
@ -17,6 +21,7 @@ require "metatable"
|
||||
require "type_mismatch"
|
||||
require "upvalues"
|
||||
require "dump_table"
|
||||
require "function"
|
||||
|
||||
if os.getenv("STRESS") then
|
||||
require "channel-stress"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user