implement lua object as Value

remove LuaJIT/Obj
remove nf7::luajit::Obj
add nf7::NodeRootLambda
This commit is contained in:
falsycat 2022-08-24 19:18:02 +09:00
parent cdf2760d2f
commit cec3f79321
11 changed files with 212 additions and 433 deletions

View File

@ -79,7 +79,6 @@ target_sources(nf7
common/logger_ref.hh
common/luajit.hh
common/luajit.cc
common/luajit_obj.hh
common/luajit_queue.hh
common/luajit_ref.hh
common/luajit_thread.hh
@ -90,6 +89,7 @@ target_sources(nf7
common/native_file.hh
common/node.hh
common/node_link_store.hh
common/node_root_lambda.hh
common/ptr_selector.hh
common/queue.hh
common/sequencer.hh
@ -115,7 +115,6 @@ target_sources(nf7
file/luajit_context.cc
file/luajit_inline_node.cc
file/luajit_node.cc
file/luajit_obj.cc
file/node_imm.cc
file/node_network.cc
file/node_ref.cc

View File

@ -59,14 +59,15 @@ void FileHolder::SetUp() noexcept {
watcher_->AddHandler(nf7::File::Event::kRemove, [this](auto&) {
file_ = nullptr;
});
if (mem) {
watcher_->AddHandler(nf7::File::Event::kUpdate, [this, mem](auto&) {
watcher_->AddHandler(nf7::File::Event::kUpdate, [this, mem](auto&) {
if (mem) {
auto ptag = std::exchange(tag_, mem->Save());
if (ptag != tag_) {
onChildMementoChange();
}
});
}
}
onChildUpdate();
});
}
// memento setup

View File

@ -103,7 +103,10 @@ class FileHolder : public nf7::FileBase::Feature {
return own()? nf7::File::Path {{id_}}: std::get<nf7::File::Path>(entity_);
}
// called when child's memento tag id is changed
// called when kUpdate event is caused by the child
std::function<void(void)> onChildUpdate = [](){};
// called when the child's memento tag id is changed
std::function<void(void)> onChildMementoChange = [](){};
// called right before returning from Emplace()

View File

@ -240,8 +240,7 @@ class Future final {
return *this;
}
}
assert(imm_);
ctx->env().ExecSub(ctx, std::bind(f, Future(*imm_)));
ctx->env().ExecSub(ctx, std::bind(f, *this));
return *this;
}

View File

@ -1,27 +0,0 @@
#pragma once
#include <future>
#include <memory>
#include "nf7.hh"
#include "common/future.hh"
#include "common/luajit_queue.hh"
#include "common/luajit_ref.hh"
namespace nf7::luajit {
class Obj : public nf7::File::Interface {
public:
Obj() = default;
Obj(const Obj&) = delete;
Obj(Obj&&) = delete;
Obj& operator=(const Obj&) = delete;
Obj& operator=(Obj&&) = delete;
// result is registered to LUA_REGISTRY
virtual nf7::Future<std::shared_ptr<Ref>> Build() noexcept = 0;
};
} // namespace nf7::luajit

View File

@ -7,11 +7,12 @@
#include "nf7.hh"
#include "common/luajit_queue.hh"
#include "common/value.hh"
namespace nf7::luajit {
class Ref final {
class Ref final : public nf7::Value::Data {
public:
Ref() = delete;
Ref(const std::shared_ptr<nf7::Context>& ctx,

View File

@ -7,7 +7,6 @@
#include <tuple>
#include "common/async_buffer.hh"
#include "common/luajit_obj.hh"
namespace nf7::luajit {
@ -19,11 +18,6 @@ constexpr size_t kBufferSizeMax = 64 * 1024 * 1024;
// Pushes a metatable for Thread object, available on global table as 'nf7'.
static void PushMeta(lua_State*) noexcept;
// Pushes Lua object built by a file who implements luajit::Obj interface.
static void GetLuaObjAndPush(
lua_State* L, const std::shared_ptr<Thread>& th, File& f);
lua_State* Thread::Init(lua_State* L) noexcept {
assert(state_ == kInitial);
@ -107,6 +101,17 @@ static void PushMeta(lua_State* L) noexcept {
});
lua_setfield(L, -2, "resolve");
// nf7:ref(obj)
lua_pushcfunction(L, [](auto L) {
auto th = Thread::GetPtr(L, 1);
lua_pushvalue(L, 2);
auto ref = std::make_shared<nf7::luajit::Ref>(th->ctx(), th->ljq(), L);
PushValue(L, nf7::Value {std::move(ref)});
return 1;
});
lua_setfield(L, -2, "ref");
// nf7:query(file_id, interface)
lua_pushcfunction(L, [](auto L) {
auto th = Thread::GetPtr(L, 1);
@ -121,7 +126,7 @@ static void PushMeta(lua_State* L) noexcept {
} else if (iface == "exbuffer") {
Thread::Lock<nf7::AsyncBuffer>::AcquireAndPush(L, th, f, true);
} else if (iface == "lua") {
GetLuaObjAndPush(L, th, f);
// WIP GetLuaObjAndPush(L, th, f);
} else if (iface == "node") {
Thread::Lambda::CreateAndPush(L, th, f);
} else {
@ -185,23 +190,4 @@ static void PushMeta(lua_State* L) noexcept {
}
}
static void GetLuaObjAndPush(
lua_State* L, const std::shared_ptr<Thread>& th, File& f) {
f.interfaceOrThrow<nf7::luajit::Obj>().Build().
Then([th, L](auto fu) {
th->ljq()->Push(th->ctx(), [th, L, fu](auto) mutable {
try {
const auto& obj = fu.value();
if (th->ljq() != obj->ljq()) {
throw nf7::Exception {"the object is built on other LuaJIT context"};
}
obj->PushSelf(L);
th->Resume(L, 1);
} catch (nf7::Exception& e) {
th->Resume(L, luajit::PushAll(L, nullptr, e.msg()));
}
});
});
}
} // namespace nf7::luajit

119
common/node_root_lambda.hh Normal file
View File

@ -0,0 +1,119 @@
#pragma once
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include "nf7.hh"
#include "common/future.hh"
#include "common/value.hh"
namespace nf7 {
class NodeRootLambda final : public nf7::Node::Lambda,
public std::enable_shared_from_this<NodeRootLambda> {
public:
struct Builder;
NodeRootLambda(const NodeRootLambda&) = delete;
NodeRootLambda(NodeRootLambda&&) = delete;
NodeRootLambda& operator=(const NodeRootLambda&) = delete;
NodeRootLambda& operator=(NodeRootLambda&&) = delete;
bool KeepAlive() noexcept {
if (target_.expired() && pro_.size()) {
for (auto& pro : pro_) {
pro.second.Throw(std::make_exception_ptr(
nf7::Exception {"output was never satisified"}));
}
}
return !target_.expired();
}
private:
std::weak_ptr<nf7::Node::Lambda> target_;
std::unordered_map<std::string, nf7::Future<nf7::Value>::Promise> pro_;
std::unordered_map<std::string, std::function<void(const nf7::Value&)>> handler_;
using nf7::Node::Lambda::Lambda;
void Handle(std::string_view name, const nf7::Value& v,
const std::shared_ptr<nf7::Node::Lambda>&) noexcept override {
const auto sname = std::string {name};
auto pitr = pro_.find(sname);
if (pitr != pro_.end()) {
pitr->second.Return(nf7::Value {v});
pro_.erase(pitr);
}
auto hitr = handler_.find(sname);
if (hitr != handler_.end()) {
hitr->second(v);
}
}
};
struct NodeRootLambda::Builder final {
public:
Builder() = delete;
Builder(nf7::File& f, nf7::Node& n,
const std::shared_ptr<nf7::Context>& ctx = nullptr) noexcept :
prod_(new NodeRootLambda {f, ctx}), target_(n.CreateLambda(prod_)), node_(&n) {
prod_->target_ = target_;
}
void CheckOutput(std::string_view name) const {
auto out = node_->GetOutputs();
if (out.end() == std::find(out.begin(), out.end(), name)) {
throw nf7::Exception {"required output is missing: "+std::string {name}};
}
}
void CheckInput(std::string_view name) const {
auto in = node_->GetInputs();
if (in.end() == std::find(in.begin(), in.end(), name)) {
throw nf7::Exception {"required input is missing: "+std::string {name}};
}
}
nf7::Future<nf7::Value> Receive(const std::string& name) {
assert(!built_);
CheckOutput(name);
auto [itr, added] =
prod_->pro_.try_emplace(name, nf7::Future<nf7::Value>::Promise {});
assert(added);
return itr->second.future();
}
void Listen(const std::string& name, std::function<void(const nf7::Value&)>&& f) {
assert(!built_);
CheckOutput(name);
prod_->handler_[name] = std::move(f);
}
std::shared_ptr<NodeRootLambda> Build() noexcept {
assert(!built_);
built_ = true;
return prod_;
}
void Send(std::string_view name, const nf7::Value& v) noexcept {
assert(built_);
CheckInput(name);
target_->Handle(name, v, prod_);
}
private:
bool built_ = false;
std::shared_ptr<NodeRootLambda> prod_;
std::shared_ptr<nf7::Node::Lambda> target_;
nf7::Node* const node_;
};
} // namespace nf7

View File

@ -17,6 +17,7 @@
#include "common/dir_item.hh"
#include "common/file_base.hh"
#include "common/file_holder.hh"
#include "common/future.hh"
#include "common/generic_context.hh"
#include "common/generic_type_info.hh"
#include "common/generic_memento.hh"
@ -24,14 +25,13 @@
#include "common/gui_popup.hh"
#include "common/life.hh"
#include "common/logger_ref.hh"
#include "common/luajit_obj.hh"
#include "common/luajit_queue.hh"
#include "common/luajit_ref.hh"
#include "common/luajit_thread.hh"
#include "common/memento.hh"
#include "common/node.hh"
#include "common/node_root_lambda.hh"
#include "common/ptr_selector.hh"
#include "common/task.hh"
#include "common/util_string.hh"
@ -62,13 +62,11 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
Node(Env& env, Data&& data = {}) noexcept :
nf7::FileBase(kType, env, {&obj_, &obj_editor_, &socket_popup_}),
nf7::DirItem(nf7::DirItem::kMenu |
nf7::DirItem::kTooltip |
nf7::DirItem::kWidget),
nf7::DirItem(nf7::DirItem::kTooltip | nf7::DirItem::kWidget),
life_(*this),
log_(std::make_shared<nf7::LoggerRef>()),
obj_(*this, "obj_factory"),
obj_editor_(obj_, [](auto& t) { return t.flags().contains("nf7::luajit::Obj"); }),
obj_editor_(obj_, [](auto& t) { return t.flags().contains("nf7::Node"); }),
mem_(std::move(data)) {
mem_.data().obj.SetTarget(obj_);
mem_.CommitAmend();
@ -83,6 +81,13 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
});
};
obj_.onChildUpdate = [this]() {
if (fu_) {
log_->Info("factory update detected, dropping cache");
}
fu_ = std::nullopt;
};
obj_.onChildMementoChange = [this]() { mem_.Commit(); };
obj_.onEmplace = [this]() { mem_.Commit(); };
@ -113,7 +118,7 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
}
void Handle(const Event&) noexcept override;
void UpdateMenu() noexcept override;
void Update() noexcept override;
void UpdateTooltip() noexcept override;
void UpdateWidget() noexcept override;
@ -127,8 +132,6 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
std::shared_ptr<nf7::LoggerRef> log_;
nf7::Task<std::shared_ptr<nf7::luajit::Ref>>::Holder fetch_;
nf7::FileHolder obj_;
nf7::gui::FileHolderEditor obj_editor_;
@ -138,26 +141,41 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
const Data& data() const noexcept { return mem_.data(); }
Data& data() noexcept { return mem_.data(); }
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> FetchHandler() noexcept;
// factory context
std::shared_ptr<nf7::NodeRootLambda> factory_;
std::optional<nf7::Future<nf7::Value>> fu_;
};
class Node::Lambda final : public nf7::Node::Lambda,
public std::enable_shared_from_this<Node::Lambda> {
public:
Lambda(Node& f, const std::shared_ptr<nf7::Node::Lambda>& parent) noexcept :
nf7::Node::Lambda(f, parent), file_(f.life_), log_(f.log_) {
nf7::Node::Lambda(f, parent), f_(f.life_), log_(f.log_) {
}
void Handle(std::string_view name, const nf7::Value& v,
void Handle(std::string_view k, const nf7::Value& v,
const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept override
try {
file_.EnforceAlive();
auto fu = file_->FetchHandler();
f_.EnforceAlive();
auto self = shared_from_this();
fu.ThenSub(self, [self, name = std::string(name), v = v, caller](auto fu) mutable {
self->CallHandler({std::move(name), std::move(v)}, fu, caller);
if (!f_->fu_) {
auto& n = f_->obj_.GetFileOrThrow().interfaceOrThrow<nf7::Node>();
auto b = nf7::NodeRootLambda::Builder {*f_, n};
f_->fu_ = b.Receive("product");
f_->factory_ = b.Build();
b.Send("create", nf7::Value::Pulse {});
}
assert(f_->fu_);
f_->fu_->ThenSub(self, [this, k = std::string {k}, v = v, caller](auto fu) mutable {
try {
auto ref = fu.value().template data<nf7::luajit::Ref>();
CallFunc(ref, std::move(k), std::move(v), caller);
} catch (nf7::Exception& e) {
log_->Error("failed to call lua function: "+e.msg());
}
});
} catch (nf7::LifeExpiredException&) {
} catch (nf7::Exception& e) {
@ -172,7 +190,7 @@ class Node::Lambda final : public nf7::Node::Lambda,
}
private:
nf7::Life<Node>::Ref file_;
nf7::Life<Node>::Ref f_;
std::shared_ptr<nf7::LoggerRef> log_;
@ -181,35 +199,45 @@ class Node::Lambda final : public nf7::Node::Lambda,
std::optional<nf7::luajit::Ref> ctxtable_;
using Param = std::pair<std::string, nf7::Value>;
void CallHandler(Param&& p, auto& fu, const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept
try {
void CallFunc(const std::shared_ptr<nf7::luajit::Ref>& func,
std::string&& k, nf7::Value&& v,
const std::shared_ptr<nf7::Node::Lambda>& caller) {
auto self = shared_from_this();
th_.erase(
std::remove_if(th_.begin(), th_.end(), [](auto& x) { return x.expired(); }),
th_.end());
auto handler = fu.value();
auto ljq = handler->ljq();
auto th = std::make_shared<nf7::luajit::Thread>(
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); });
th->Install(log_);
th_.emplace_back(th);
ljq->Push(self, [this, self, ljq, p = std::move(p), caller, handler, th](auto L) mutable {
ljq->Push(self, [this, self, ljq, k = std::move(k), v = std::move(v), caller, func, th](auto L) mutable {
auto thL = th->Init(L);
handler->PushSelf(thL);
lua_pushstring(thL, p.first.c_str());
nf7::luajit::PushValue(thL, p.second);
func->PushSelf(thL);
// push args
lua_pushstring(thL, k.c_str());
nf7::luajit::PushValue(thL, v);
nf7::luajit::PushNodeLambda(thL, caller, self);
PushContextTable(ljq, thL);
// push context table
if (ctxtable_ && ctxtable_->ljq() != ljq) {
ctxtable_ = std::nullopt;
}
if (!ctxtable_) {
lua_createtable(thL, 0, 0);
lua_pushvalue(thL, -1);
ctxtable_.emplace(shared_from_this(), ljq, thL);
} else {
ctxtable_->PushSelf(thL);
}
// execute
th->Resume(thL, 4);
});
} catch (nf7::Exception& e) {
log_->Error("failed to call handler: "+e.msg());
}
void HandleThread(const std::shared_ptr<nf7::luajit::Queue>& ljq,
nf7::luajit::Thread& th, lua_State* L) noexcept {
switch (th.state()) {
@ -227,20 +255,6 @@ class Node::Lambda final : public nf7::Node::Lambda,
return;
}
}
void PushContextTable(const std::shared_ptr<nf7::luajit::Queue>& ljq,
lua_State* L) noexcept {
if (ctxtable_ && ctxtable_->ljq() != ljq) {
ctxtable_ = std::nullopt;
}
if (!ctxtable_) {
lua_createtable(L, 0, 0);
lua_pushvalue(L, -1);
ctxtable_.emplace(shared_from_this(), ljq, L);
} else {
ctxtable_->PushSelf(L);
}
}
};
@ -248,12 +262,6 @@ std::shared_ptr<nf7::Node::Lambda> Node::CreateLambda(
const std::shared_ptr<nf7::Node::Lambda>& parent) noexcept {
return std::make_shared<Lambda>(*this, parent);
}
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Node::FetchHandler() noexcept
try {
return obj_.GetFileOrThrow().interfaceOrThrow<nf7::luajit::Obj>().Build();
} catch (nf7::Exception&) {
return {std::current_exception()};
}
void Node::Handle(const Event& ev) noexcept {
nf7::FileBase::Handle(ev);
@ -271,9 +279,11 @@ void Node::Handle(const Event& ev) noexcept {
return;
}
}
void Node::UpdateMenu() noexcept {
if (ImGui::MenuItem("fetch handler")) {
FetchHandler();
void Node::Update() noexcept {
nf7::FileBase::Update();
if (factory_) {
factory_->KeepAlive();
}
}
void Node::UpdateTooltip() noexcept {

View File

@ -1,312 +0,0 @@
#include <atomic>
#include <exception>
#include <memory>
#include <string_view>
#include <utility>
#include <vector>
#include <imgui.h>
#include <imgui_stdlib.h>
#include <yas/serialize.hpp>
#include "nf7.hh"
#include "common/async_buffer.hh"
#include "common/dir_item.hh"
#include "common/file_base.hh"
#include "common/file_holder.hh"
#include "common/future.hh"
#include "common/generic_context.hh"
#include "common/generic_type_info.hh"
#include "common/generic_memento.hh"
#include "common/generic_watcher.hh"
#include "common/gui_file.hh"
#include "common/life.hh"
#include "common/lock.hh"
#include "common/luajit.hh"
#include "common/luajit_obj.hh"
#include "common/luajit_queue.hh"
#include "common/luajit_thread.hh"
#include "common/logger_ref.hh"
#include "common/ptr_selector.hh"
#include "common/task.hh"
#include "common/yas_nf7.hh"
using namespace std::literals;
namespace nf7 {
namespace {
class Obj final : public nf7::FileBase, public nf7::DirItem, public nf7::luajit::Obj {
public:
static inline const nf7::GenericTypeInfo<Obj> kType = {
"LuaJIT/Obj", {"nf7::DirItem", "nf7::luajit::Obj"}};
static void UpdateTypeTooltip() noexcept {
ImGui::TextUnformatted(
"Compiles and runs LuaJIT script, and caches the object returned from the script.");
ImGui::Bullet(); ImGui::TextUnformatted(
"implements nf7::luajit::Obj implementation");
ImGui::Bullet(); ImGui::TextUnformatted(
"requires nf7::luajit::Queue implementation with name '_luajit' on upper dir");
ImGui::Bullet(); ImGui::TextUnformatted(
"requires nf7::AsyncBuffer implementation to load LuaJIT script");
}
static constexpr size_t kMaxSize = 1024*1024*16; /* = 16 MiB */
class ExecTask;
struct Data final {
nf7::FileHolder::Tag src;
};
Obj(Env& env, Data&& data = {}) noexcept :
nf7::FileBase(kType, env, {&src_, &src_editor_}),
nf7::DirItem(nf7::DirItem::kTooltip |
nf7::DirItem::kMenu |
nf7::DirItem::kWidget),
life_(*this),
log_(std::make_shared<nf7::LoggerRef>()),
src_(*this, "src"),
src_editor_(src_, [](auto& t) { return t.flags().contains("nf7::AsyncBuffer"); }),
mem_(std::move(data)) {
mem_.data().src.SetTarget(src_);
mem_.CommitAmend();
src_.onChildMementoChange = [this]() { mem_.Commit(); };
src_.onEmplace = [this]() { mem_.Commit(); };
mem_.onRestore = [this]() { DropCache(); Touch(); };
mem_.onCommit = [this]() { DropCache(); Touch(); };
}
Obj(Env& env, Deserializer& ar) noexcept : Obj(env) {
ar(src_);
}
void Serialize(Serializer& ar) const noexcept override {
ar(src_);
}
std::unique_ptr<File> Clone(Env& env) const noexcept override {
return std::make_unique<Obj>(env, Data {mem_.data()});
}
void Handle(const Event&) noexcept override;
void UpdateMenu() noexcept override;
void UpdateTooltip() noexcept override;
void UpdateWidget() noexcept override;
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Build() noexcept override;
File::Interface* interface(const std::type_info& t) noexcept override {
return nf7::InterfaceSelector<
nf7::DirItem, nf7::luajit::Obj, nf7::Memento>(t).Select(this, &mem_);
}
private:
nf7::Life<Obj> life_;
std::shared_ptr<nf7::LoggerRef> log_;
std::optional<nf7::GenericWatcher> watcher_;
std::shared_ptr<nf7::luajit::Ref> cache_;
nf7::Task<std::shared_ptr<nf7::luajit::Ref>>::Holder exec_;
nf7::FileHolder src_;
nf7::gui::FileHolderEditor src_editor_;
nf7::GenericMemento<Data> mem_;
void DropCache() noexcept;
};
class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>> {
public:
ExecTask(Obj& target) noexcept :
Task(target.env(), target.id()), target_(&target), log_(target.log_) {
}
size_t GetMemoryUsage() const noexcept override {
return buf_size_;
}
private:
Obj* const target_;
std::shared_ptr<nf7::LoggerRef> log_;
std::string chunkname_;
std::atomic<size_t> buf_size_ = 0;
std::vector<uint8_t> buf_;
bool buf_consumed_ = false;
nf7::Future<std::shared_ptr<nf7::luajit::Ref>>::Coro Proc() noexcept override {
try {
auto& srcf = target_->src_.GetFileOrThrow();
chunkname_ = srcf.abspath().Stringify();
const auto srcf_id = srcf.id();
// acquire lock of source
auto src = srcf.interfaceOrThrow<nf7::AsyncBuffer>().self();
auto srclock = co_await src->AcquireLock(false);
// get size of source
buf_size_ = co_await src->size();
if (buf_size_ == 0) {
throw nf7::Exception("source is empty");
}
if (buf_size_ > kMaxSize) {
throw nf7::Exception("source is too huge");
}
// read source
buf_.resize(buf_size_);
const size_t read = co_await src->Read(0, buf_.data(), buf_size_);
if (read != buf_size_) {
throw nf7::Exception("failed to read all bytes from source");
}
// find luajit queue
auto ljq = target_->
ResolveUpwardOrThrow("_luajit").
interfaceOrThrow<nf7::luajit::Queue>().self();
// create promise handler for new luajit thread
nf7::Future<int>::Promise lua_pro(self());
auto handler = nf7::luajit::Thread::CreatePromiseHandler<int>(
lua_pro, [&](auto L) {
if (lua_gettop(L) != 1) {
throw nf7::Exception("expected one object to be returned");
}
return luaL_ref(L, LUA_REGISTRYINDEX);
});
// start watcher on target_->watcher_
try {
auto& w = target_->watcher_;
w.emplace(env());
w->Watch(srcf_id);
std::weak_ptr<Task> wself = self();
w->AddHandler(Event::kUpdate, [t = target_, wself](auto&) {
if (auto self = wself.lock()) {
t->log_->Info("detected update of source file, aborts building");
t->exec_ = {};
} else if (t->cache_) {
t->log_->Info("detected update of source file, drops cache automatically");
t->cache_ = nullptr;
t->Touch();
}
});
} catch (Exception& e) {
log_->Warn("watcher setup error: "+e.msg());
}
// queue task to trigger the thread
auto th = std::make_shared<nf7::luajit::Thread>(self(), ljq, std::move(handler));
th->Install(log_);
ljq->Push(self(), [&](auto L) {
try {
auto thL = th->Init(L);
Compile(thL);
th->Resume(thL, 0);
} catch (Exception&) {
lua_pro.Throw(std::current_exception());
}
});
// wait for end of execution and return built object's index
const int idx = co_await lua_pro.future();
// context for object cache
auto ctx = std::make_shared<nf7::GenericContext>(env(), initiator(), "luajit object cache");
// return the object and cache it
target_->cache_ = std::make_shared<nf7::luajit::Ref>(ctx, ljq, idx);
co_yield target_->cache_;
} catch (Exception& e) {
throw;
}
}
void Compile(lua_State* L) {
static const auto kReader = [](lua_State*, void* selfptr, size_t* size) -> const char* {
auto self = reinterpret_cast<ExecTask*>(selfptr);
if (std::exchange(self->buf_consumed_, true)) {
*size = 0;
return nullptr;
} else {
*size = self->buf_.size();
return reinterpret_cast<const char*>(self->buf_.data());
}
};
if (0 != lua_load(L, kReader, this, chunkname_.c_str())) {
throw nf7::Exception(lua_tostring(L, -1));
}
}
};
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Obj::Build() noexcept {
if (auto exec = exec_.lock()) return exec->fu();
if (cache_) {
return std::shared_ptr<nf7::luajit::Ref>{cache_};
}
auto exec = std::make_shared<ExecTask>(*this);
exec->Start();
exec_ = {exec};
return exec->fu();
}
void Obj::Handle(const Event& ev) noexcept {
nf7::FileBase::Handle(ev);
switch (ev.type) {
case Event::kAdd:
log_->SetUp(*this);
break;
case Event::kRemove:
DropCache();
log_->TearDown();
break;
default:
break;
}
}
void Obj::DropCache() noexcept {
exec_ = {};
cache_ = nullptr;
watcher_ = std::nullopt;
}
void Obj::UpdateMenu() noexcept {
if (ImGui::MenuItem("build")) {
Build();
}
if (ImGui::MenuItem("drop cache", nullptr, nullptr, !!cache_)) {
DropCache();
}
}
void Obj::UpdateTooltip() noexcept {
ImGui::Text("cache: %s", cache_? "ready": "nothing");
ImGui::Text("src :");
ImGui::Indent();
src_editor_.Tooltip();
ImGui::Unindent();
}
void Obj::UpdateWidget() noexcept {
ImGui::TextUnformatted("LuaJIT/Obj: config");
src_editor_.ButtonWithLabel("src");
ImGui::Spacing();
src_editor_.ItemWidget("src");
}
}
} // namespace nf7

View File

@ -49,7 +49,7 @@ namespace {
class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
public:
static inline const GenericTypeInfo<Network> kType = {
"Node/Network", {"nf7::DirItem", ""}};
"Node/Network", {"nf7::DirItem", "nf7::Node"}};
static void UpdateTypeTooltip() noexcept {
ImGui::TextUnformatted("A Node composed of multiple child Nodes, whose sockets are linked to each other");
ImGui::Bullet(); ImGui::TextUnformatted("implements nf7::Node");