replace to nf7:yield() from a custom type of Node::Lambda in Lua script

This commit is contained in:
2022-08-27 00:26:10 +09:00
parent 2e25e6d14c
commit a703ba3bbc
6 changed files with 51 additions and 87 deletions

View File

@@ -368,43 +368,6 @@ void PushMutableVector(lua_State* L, std::vector<uint8_t>&& v) noexcept {
lua_setmetatable(L, -2);
}
void PushNodeLambda(lua_State* L,
const std::shared_ptr<nf7::Node::Lambda>& callee,
const std::weak_ptr<nf7::Node::Lambda>& caller) noexcept {
constexpr auto kTypeName = "nf7::Node::Lambda";
struct Data {
std::shared_ptr<nf7::Node::Lambda> callee;
std::weak_ptr<nf7::Node::Lambda> caller;
};
new (lua_newuserdata(L, sizeof(Data))) Data { .callee = callee, .caller = caller };
if (luaL_newmetatable(L, kTypeName)) {
lua_pushcfunction(L, [](auto L) {
const auto& d = *reinterpret_cast<Data*>(luaL_checkudata(L, 1, kTypeName));
auto caller = d.caller.lock();
if (!caller) return luaL_error(L, "caller expired");
std::string n = luaL_checkstring(L, 2);
auto v = nf7::luajit::CheckValue(L, 3);
auto callee = d.callee;
callee->env().ExecSub(callee, [callee, caller, n = std::move(n), v = std::move(v)]() {
callee->Handle(n, v, caller);
});
return 0;
});
lua_setfield(L, -2, "__call");
lua_pushcfunction(L, [](auto L) {
reinterpret_cast<Data*>(luaL_checkudata(L, 1, kTypeName))->~Data();
return 0;
});
lua_setfield(L, -2, "__gc");
}
lua_setmetatable(L, -2);
}
std::optional<nf7::Value> ToValue(lua_State* L, int idx) noexcept {
if (lua_isnoneornil(L, idx)) {

View File

@@ -9,7 +9,6 @@
#include <lua.hpp>
#include "common/node.hh"
#include "common/value.hh"
@@ -20,9 +19,6 @@ void PushImmEnv(lua_State*) noexcept;
void PushValue(lua_State*, const nf7::Value&) noexcept;
void PushVector(lua_State*, const nf7::Value::ConstVector&) noexcept;
void PushMutableVector(lua_State*, std::vector<uint8_t>&&) noexcept;
void PushNodeLambda(lua_State*,
const std::shared_ptr<nf7::Node::Lambda>& callee,
const std::weak_ptr<nf7::Node::Lambda>& caller) noexcept;
std::optional<nf7::Value> ToValue(lua_State*, int) noexcept;
std::optional<nf7::Value::ConstVector> ToVector(lua_State*, int) noexcept;

View File

@@ -147,9 +147,6 @@ static void PushMeta(lua_State* L) noexcept {
// nf7:yield(results...)
lua_pushcfunction(L, [](auto L) {
auto th = Thread::GetPtr(L, 1);
th->ExecResume(L);
th->ExpectYield(L);
return lua_yield(L, lua_gettop(L)-1);
});
lua_setfield(L, -2, "yield");

View File

@@ -5,6 +5,7 @@
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
@@ -17,6 +18,7 @@
#include "common/logger_ref.hh"
#include "common/luajit.hh"
#include "common/luajit_ref.hh"
#include "common/node.hh"
namespace nf7::luajit {
@@ -40,9 +42,14 @@ class Thread final : public std::enable_shared_from_this<Thread> {
// Creates a handler to finalize a promise.
template <typename T>
static Handler CreatePromiseHandler(
static inline Handler CreatePromiseHandler(
nf7::Future<T>::Promise& pro, std::function<T(lua_State*)>&&) noexcept;
// Creates a handler to emit yielded value to Node::Lambda.
static inline Handler CreateNodeLambdaHandler(
const std::shared_ptr<nf7::Node::Lambda>& caller,
const std::shared_ptr<nf7::Node::Lambda>& callee) noexcept;
// must be called on luajit thread
static std::shared_ptr<Thread> GetPtr(lua_State* L, int idx) {
auto th = CheckWeakPtr<Thread>(L, idx, kTypeName);
@@ -176,4 +183,42 @@ Thread::Handler Thread::CreatePromiseHandler(
};
}
Thread::Handler Thread::CreateNodeLambdaHandler(
const std::shared_ptr<nf7::Node::Lambda>& caller,
const std::shared_ptr<nf7::Node::Lambda>& callee) noexcept {
return [caller, callee](auto& th, auto L) {
switch (th.state()) {
case nf7::luajit::Thread::kPaused:
switch (lua_gettop(L)) {
case 0:
th.ExecResume(L);
return;
case 2: {
auto k = luaL_checkstring(L, 1);
auto v = nf7::luajit::CheckValue(L, 2);
caller->env().ExecSub(
caller, [caller, callee, k = std::string {k}, v = std::move(v)]() {
caller->Handle(k, v, callee);
});
} return;
default:
if (auto log = th.logger()) {
log->Warn("invalid use of yield, nf7:yield() or nf7:yield(name, value)");
}
th.Resume(L, 0);
return;
}
case nf7::luajit::Thread::kFinished:
return;
default:
if (auto log = th.logger()) {
log->Warn(std::string {"luajit execution error: "}+lua_tostring(L, -1));
}
return;
}
};
}
} // namespace nf7::luajit

View File

@@ -138,7 +138,7 @@ class InlineNode::Lambda final : public nf7::Node::Lambda,
auto self = shared_from_this();
auto th = std::make_shared<nf7::luajit::Thread>(
self, ljq,
[self, ljq](auto& th, auto L) { self->HandleThread(ljq, th, L); });
nf7::luajit::Thread::CreateNodeLambdaHandler(caller, shared_from_this()));
th->Install(log_);
th_.emplace_back(th);
@@ -165,7 +165,6 @@ class InlineNode::Lambda final : public nf7::Node::Lambda,
// push args
lua_pushstring(thL, p.first.c_str()); // key
nf7::luajit::PushValue(thL, p.second); // value
nf7::luajit::PushNodeLambda(thL, caller, self); // caller
// push ctx table
if (ctxtable_ && ctxtable_->ljq() != ljq) {
@@ -181,7 +180,7 @@ class InlineNode::Lambda final : public nf7::Node::Lambda,
}
// start function
th->Resume(thL, 4);
th->Resume(thL, 3);
});
} catch (nf7::LifeExpiredException&) {
@@ -209,25 +208,6 @@ class InlineNode::Lambda final : public nf7::Node::Lambda,
// used on luajit thread
std::optional<nf7::luajit::Ref> func_;
std::optional<nf7::luajit::Ref> ctxtable_;
void HandleThread(const std::shared_ptr<nf7::luajit::Queue>& ljq,
nf7::luajit::Thread& th, lua_State* L) noexcept {
switch (th.state()) {
case nf7::luajit::Thread::kFinished:
return;
case nf7::luajit::Thread::kPaused:
log_->Warn("unexpected yield");
ljq->Push(shared_from_this(),
[th = th.shared_from_this(), L](auto) { th->Resume(L, 0); });
return;
default:
log_->Warn("luajit execution error: "s+lua_tostring(L, -1));
return;
}
}
};

View File

@@ -204,7 +204,8 @@ class Node::Lambda final : public nf7::Node::Lambda,
auto ljq = func->ljq();
auto th = std::make_shared<nf7::luajit::Thread>(
self, ljq, [self, ljq](auto& th, auto L) { self->HandleThread(ljq, th, L); });
self, ljq,
nf7::luajit::Thread::CreateNodeLambdaHandler(caller, shared_from_this()));
th->Install(log_);
th_.emplace_back(th);
@@ -215,7 +216,6 @@ class Node::Lambda final : public nf7::Node::Lambda,
// push args
lua_pushstring(thL, k.c_str());
nf7::luajit::PushValue(thL, v);
nf7::luajit::PushNodeLambda(thL, caller, self);
// push context table
if (ctxtable_ && ctxtable_->ljq() != ljq) {
@@ -230,26 +230,9 @@ class Node::Lambda final : public nf7::Node::Lambda,
}
// execute
th->Resume(thL, 4);
th->Resume(thL, 3);
});
}
void HandleThread(const std::shared_ptr<nf7::luajit::Queue>& ljq,
nf7::luajit::Thread& th, lua_State* L) noexcept {
switch (th.state()) {
case nf7::luajit::Thread::kFinished:
return;
case nf7::luajit::Thread::kPaused:
log_->Warn("unexpected yield");
ljq->Push(shared_from_this(),
[th = th.shared_from_this(), L](auto) { th->Resume(L, 0); });
return;
default:
log_->Warn("luajit execution error: "s+lua_tostring(L, -1));
return;
}
}
};