replace FileRef to FileHolder

This commit is contained in:
falsycat 2022-08-22 13:34:50 +09:00
parent 02cc9bf49d
commit 121209161a
11 changed files with 223 additions and 354 deletions

View File

@ -54,7 +54,6 @@ target_sources(nf7
common/file_base.hh
common/file_holder.hh
common/file_holder.cc
common/file_ref.hh
common/future.hh
common/generic_context.hh
common/generic_history.hh

View File

@ -111,14 +111,19 @@ FileHolder::Tag::Tag(const Tag& src) noexcept {
}
}
FileHolder::Tag& FileHolder::Tag::operator=(const Tag& src) noexcept {
assert(!src.target_);
assert(target_);
target_->TearDown();
target_->entity_ = src.entity_;
target_->tag_ = src.tag_;
target_->SetUp();
if (!src.target_ && target_) {
// restore
target_->TearDown();
target_->entity_ = src.entity_;
target_->tag_ = src.tag_;
target_->SetUp();
} else if (!src.target_ && !target_) {
// copy
entity_ = src.entity_;
tag_ = src.tag_;
} else {
assert(false);
}
return *this;
}

View File

@ -89,6 +89,7 @@ class FileHolder : public nf7::FileBase::Feature {
}
nf7::File& owner() const noexcept { return *owner_; }
const std::string& id() const noexcept { return id_; }
nf7::File* file() const noexcept { return file_; }
nf7::File::Path path() const noexcept {
@ -121,6 +122,7 @@ class FileHolder : public nf7::FileBase::Feature {
// to save/restore FileHolder's changes through GenericMemento
class FileHolder::Tag final {
public:
Tag() = default;
Tag(nf7::FileHolder& target) noexcept : target_(&target) {
}
Tag(const Tag&) noexcept;

View File

@ -1,89 +0,0 @@
#pragma once
#include <utility>
#include <yas/serialize.hpp>
#include <yas/types/utility/usertype.hpp>
#include "nf7.hh"
#include "common/yas_nf7.hh"
namespace nf7 {
class FileRef {
public:
FileRef() = delete;
FileRef(File& owner) noexcept : owner_(&owner) {
}
FileRef(File& owner, const File::Path& p, File::Id id = 0) noexcept :
owner_(&owner), path_({p}), id_(id) {
}
FileRef(File& owner, File::Path&& p, File::Id id = 0) noexcept :
owner_(&owner), path_(std::move(p)), id_(id) {
}
FileRef(const FileRef&) = default;
FileRef(FileRef&&) = default;
FileRef& operator=(const FileRef&) = default;
FileRef& operator=(FileRef&&) = default;
File& operator*() const
try {
return owner_->env().GetFileOrThrow(id_);
} catch (ExpiredException&) {
auto& ret = owner_->ResolveOrThrow(path_);
const_cast<File::Id&>(id_) = ret.id();
return ret;
}
FileRef& operator=(const File::Path& path) noexcept {
return operator=(File::Path{path});
}
FileRef& operator=(File::Path&& path) noexcept {
if (path_ != path) {
path_ = std::move(path);
id_ = 0;
}
return *this;
}
const File::Path& path() const noexcept { return path_; }
File::Id id() const { **this; return id_; }
private:
File* owner_;
File::Path path_;
File::Id id_ = 0;
};
} // namespace nf7
namespace yas::detail {
template <size_t F>
struct serializer<
type_prop::not_a_fundamental,
ser_case::use_internal_serializer,
F,
nf7::FileRef> {
public:
template <typename Archive>
static Archive& save(Archive& ar, const nf7::FileRef& ref) {
ar(ref.path());
return ar;
}
template <typename Archive>
static Archive& load(Archive& ar, nf7::FileRef& ref) {
nf7::File::Path path;
ar(path);
ref = path;
return ar;
}
};
} // namespace yas::detail

View File

@ -35,6 +35,7 @@ class Future final {
class Coro;
using Handle = std::coroutine_handle<Promise>;
using Imm = std::variant<T, std::exception_ptr>;
enum State { kYet, kDone, kError, };
@ -203,6 +204,10 @@ class Future final {
}
Future(std::exception_ptr e) noexcept : imm_({e}) {
}
Future(const Imm& imm) noexcept : imm_(imm) {
}
Future(Imm&& imm) noexcept : imm_(std::move(imm)) {
}
Future(const Future&) = default;
Future(Future&&) = default;
Future& operator=(const Future&) = default;
@ -235,7 +240,8 @@ class Future final {
return *this;
}
}
ctx->env().ExecSub(ctx, std::bind(f, Future(data_)));
assert(imm_);
ctx->env().ExecSub(ctx, std::bind(f, Future(*imm_)));
return *this;
}
@ -304,7 +310,7 @@ class Future final {
auto await_resume() { return value(); }
private:
std::optional<std::variant<T, std::exception_ptr>> imm_;
std::optional<Imm> imm_;
std::shared_ptr<Data> data_;
Future(const std::shared_ptr<Data>& data) noexcept : data_(data) { }

View File

@ -5,6 +5,7 @@
#include <imgui.h>
#include <imgui_stdlib.h>
#include "common/dir_item.hh"
#include "common/generic_context.hh"
@ -12,6 +13,15 @@ using namespace std::literals;
namespace nf7::gui {
static nf7::DirItem* GetDirItem(nf7::FileHolder& h, nf7::DirItem::Flags f) noexcept
try {
auto& d = h.GetFileOrThrow().interfaceOrThrow<nf7::DirItem>();
return d.flags() & f? &d: nullptr;
} catch (nf7::Exception&) {
return nullptr;
}
bool FileFactory::Update() noexcept {
const auto em = ImGui::GetFontSize();
@ -116,41 +126,70 @@ std::string FileHolderEditor::GetDisplayText() const noexcept {
return text;
}
void FileHolderEditor::Button(bool small) noexcept {
void FileHolderEditor::Button(float w, bool small) noexcept {
ImGui::PushID(this);
ImGui::BeginGroup();
const auto text = GetDisplayText();
const bool open = small?
open_ |= small?
ImGui::SmallButton(text.c_str()):
ImGui::Button(text.c_str());
if (open) {
ImGui::OpenPopup("FileHolderEditorPopup");
ImGui::Button(text.c_str(), {w, 0});
if (ImGui::BeginPopupContextItem()) {
MenuItems();
ImGui::EndPopup();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s", text.c_str());
ImGui::BeginTooltip();
Tooltip();
ImGui::EndTooltip();
}
ImGui::EndGroup();
UpdatePopup();
ImGui::PopID();
}
void FileHolderEditor::ButtonWithLabel(const char* name) noexcept {
ImGui::PushID(this);
ImGui::BeginGroup();
if (ImGui::Button(GetDisplayText().c_str(), {ImGui::CalcItemWidth(), 0})) {
ImGui::OpenPopup("FileHolderEditorPopup");
}
Button(ImGui::CalcItemWidth());
ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::TextUnformatted(name);
ImGui::EndGroup();
UpdatePopup();
ImGui::PopID();
}
void FileHolderEditor::UpdatePopup() noexcept {
void FileHolderEditor::Tooltip() noexcept {
ImGui::TextUnformatted(GetDisplayText().c_str());
ImGui::Indent();
if (auto a = GetDirItem(*holder_, nf7::DirItem::kTooltip)) {
a->UpdateTooltip();
}
ImGui::Unindent();
}
void FileHolderEditor::MenuItems() noexcept {
if (ImGui::MenuItem("emplace")) {
open_ = true;
}
if (auto a = GetDirItem(*holder_, nf7::DirItem::kMenu)) {
ImGui::Separator();
a->UpdateMenu();
}
}
void FileHolderEditor::MenuWithTooltip(const char* name) noexcept {
if (ImGui::BeginMenu(name)) {
MenuItems();
ImGui::EndMenu();
}
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
Tooltip();
ImGui::EndTooltip();
}
}
void FileHolderEditor::Update() noexcept {
ImGui::PushID(this);
if (std::exchange(open_, false)) {
ImGui::OpenPopup("FileHolderEditorPopup");
}
if (ImGui::BeginPopup("FileHolderEditorPopup")) {
if (ImGui::IsWindowAppearing()) {
if (holder_->ref()) {
@ -208,6 +247,8 @@ void FileHolderEditor::UpdatePopup() noexcept {
}
ImGui::EndPopup();
}
ImGui::PopID();
}
} // namespace nf7::gui

View File

@ -7,6 +7,7 @@
#include "nf7.hh"
#include "common/file_base.hh"
#include "common/file_holder.hh"
@ -47,7 +48,7 @@ class FileFactory final {
std::string type_filter_;
};
class FileHolderEditor final {
class FileHolderEditor final : public nf7::FileBase::Feature {
public:
enum Type {
kOwn,
@ -64,18 +65,23 @@ class FileHolderEditor final {
std::string GetDisplayText() const noexcept;
void Button(bool = false) noexcept;
void SmallButton() noexcept { Button(true); }
void Button(float w = 0, bool = false) noexcept;
void SmallButton() noexcept { Button(0, true); }
void ButtonWithLabel(const char* id) noexcept;
void Tooltip() noexcept;
void MenuItems() noexcept;
void MenuWithTooltip(const char* name) noexcept;
void Update() noexcept override;
private:
nf7::FileHolder* const holder_;
bool open_ = false;
Type type_;
FileFactory factory_;
std::string path_;
void UpdatePopup() noexcept;
};
} // namespace nf7::gui

View File

@ -15,12 +15,13 @@
#include "nf7.hh"
#include "common/dir_item.hh"
#include "common/file_ref.hh"
#include "common/file_base.hh"
#include "common/file_holder.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_dnd.hh"
#include "common/gui_file.hh"
#include "common/life.hh"
#include "common/logger_ref.hh"
#include "common/luajit_obj.hh"
#include "common/luajit_queue.hh"
@ -38,33 +39,39 @@ using namespace std::literals;
namespace nf7 {
namespace {
class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
public:
static inline const GenericTypeInfo<Node> kType =
{"LuaJIT/Node", {"nf7::DirItem",}};
{"LuaJIT/Node", {"nf7::DirItem"}};
static void UpdateTypeTooltip() noexcept {
ImGui::TextUnformatted("Defines new Node using LuaJIT/Obj.");
ImGui::TextUnformatted("Defines new Node using Lua object factory.");
ImGui::Bullet();
ImGui::TextUnformatted("refers nf7::luajit::Queue through linked LuaJIT/Obj");
ImGui::Bullet();
ImGui::TextUnformatted("requires nf7::luajit::Obj to refer this Node from externals");
}
class FetchTask;
class Lambda;
struct Data {
std::string desc;
nf7::FileHolder::Tag obj;
std::string desc;
std::vector<std::string> inputs;
std::vector<std::string> outputs;
};
Node(Env& env, File::Path&& path = {}, Data&& data = {}) noexcept :
File(kType, env),
DirItem(DirItem::kMenu | DirItem::kTooltip | DirItem::kDragDropTarget),
Node(Env& env, const nf7::FileHolder* obj = nullptr, Data&& data = {}) noexcept :
nf7::FileBase(kType, env, {&obj_, &obj_editor_}),
nf7::DirItem(nf7::DirItem::kMenu | nf7::DirItem::kTooltip),
life_(*this),
log_(std::make_shared<nf7::LoggerRef>()),
obj_(*this, std::move(path)),
obj_(*this, "obj_factory", obj),
obj_editor_(obj_, [](auto& t) { return t.flags().contains("nf7::luajit::Obj"); }),
mem_(std::move(data)) {
this->data().obj = nf7::FileHolder::Tag {obj_};
mem_.CommitAmend();
obj_.onChildMementoChange = [this]() { mem_.Commit(); };
obj_.onEmplace = [this]() { mem_.Commit(); };
mem_.onRestore = [this]() { Touch(); };
mem_.onCommit = [this]() { Touch(); };
}
@ -80,7 +87,7 @@ class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
ar(obj_, data().desc, data().inputs, data().outputs);
}
std::unique_ptr<File> Clone(Env& env) const noexcept override {
return std::make_unique<Node>(env, File::Path(obj_.path()), Data {data()});
return std::make_unique<Node>(env, &obj_, Data {data()});
}
std::shared_ptr<nf7::Node::Lambda> CreateLambda(
@ -97,23 +104,23 @@ class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
static void UpdateList(std::vector<std::string>&) noexcept;
void UpdateMenu() noexcept override;
void UpdateTooltip() noexcept override;
void UpdateDragDropTarget() noexcept override;
void UpdateNode(Node::Editor&) noexcept override;
File::Interface* interface(const std::type_info& t) noexcept override {
return nf7::InterfaceSelector<nf7::DirItem, nf7::Node>(t).Select(this);
return nf7::InterfaceSelector<
nf7::DirItem, nf7::Memento, nf7::Node>(t).Select(this, &mem_);
}
private:
nf7::Life<Node> life_;
std::shared_ptr<nf7::LoggerRef> log_;
std::shared_ptr<nf7::luajit::Ref> handler_;
nf7::Task<std::shared_ptr<nf7::luajit::Ref>>::Holder fetch_;
const char* popup_ = nullptr;
nf7::FileRef obj_;
std::optional<nf7::GenericWatcher> watcher_;
nf7::FileHolder obj_;
nf7::gui::FileHolderEditor obj_editor_;
nf7::GenericMemento<Data> mem_;
const Data& data() const noexcept { return mem_.data(); }
@ -122,12 +129,6 @@ class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> FetchHandler() noexcept;
void DropHandler() noexcept {
watcher_ = std::nullopt;
handler_ = nullptr;
fetch_ = {};
}
static void Uniq(std::vector<std::string>& v) {
for (auto itr = v.begin(); itr < v.end();) {
if (v.end() != std::find(itr+1, v.end(), *itr)) {
@ -154,62 +155,26 @@ class Node final : public nf7::File, public nf7::DirItem, public nf7::Node {
}
};
class Node::FetchTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>> {
public:
FetchTask(Node& target) noexcept :
Task(target.env(), target.id()), target_(&target), log_(target_->log_) {
}
private:
Node* const target_;
std::shared_ptr<nf7::LoggerRef> log_;
nf7::Future<std::shared_ptr<nf7::luajit::Ref>>::Coro Proc() noexcept {
try {
auto& objf = *target_->obj_;
auto& obj = objf.interfaceOrThrow<nf7::luajit::Obj>();
auto handler = co_await obj.Build();
co_yield handler;
try {
*target_->obj_; // checks if objf is alive
target_->handler_ = handler;
auto& w = target_->watcher_;
w.emplace(env());
w->Watch(objf.id());
w->AddHandler(Event::kUpdate, [t = target_](auto&) {
if (t->handler_) {
t->log_->Info("detected update of handler object, drops cache");
t->handler_ = nullptr;
}
});
} catch (Exception& e) {
log_->Error("watcher setup failure: "+e.msg());
}
} catch (Exception& e) {
log_->Error("fetch failure: "+e.msg());
throw;
}
}
};
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), log_(f.log_), handler_(f.FetchHandler()) {
nf7::Node::Lambda(f, parent), file_(f.life_), log_(f.log_) {
}
void Handle(std::string_view name, const nf7::Value& v,
const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept override {
const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept override
try {
file_.EnforceAlive();
auto fu = file_->FetchHandler();
auto self = shared_from_this();
handler_.ThenSub(self, [self, name = std::string(name), v, caller](auto) mutable {
self->CallHandler({{std::move(name), std::move(v)}}, caller);
fu.ThenSub(self, [self, name = std::string(name), v = v, caller](auto fu) mutable {
self->CallHandler({std::move(name), std::move(v)}, fu, caller);
});
} catch (nf7::LifeExpiredException&) {
} catch (nf7::Exception& e) {
log_->Error(e.msg());
}
void Abort() noexcept override {
for (auto& wth : th_) {
@ -220,62 +185,53 @@ class Node::Lambda final : public nf7::Node::Lambda,
}
private:
Node* const file_;
nf7::Life<Node>::Ref file_;
std::shared_ptr<nf7::LoggerRef> log_;
nf7::Future<std::shared_ptr<nf7::luajit::Ref>> handler_;
std::shared_ptr<nf7::luajit::Queue> ljq_;
std::vector<std::weak_ptr<nf7::luajit::Thread>> th_;
std::optional<nf7::luajit::Ref> ctxtable_;
using Param = std::pair<std::string, nf7::Value>;
void CallHandler(std::optional<Param>&& p, const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept
void CallHandler(Param&& p, auto& fu, const std::shared_ptr<nf7::Node::Lambda>& caller) noexcept
try {
auto self = shared_from_this();
th_.erase(
std::remove_if(th_.begin(), th_.end(), [](auto& x) { return x.expired(); }),
th_.end());
auto handler = handler_.value();
ljq_ = handler->ljq();
auto handler = fu.value();
auto ljq = handler->ljq();
env().GetFileOrThrow(initiator()); // check if the owner is alive
auto th = std::make_shared<nf7::luajit::Thread>(
self, ljq_,
[self](auto& th, auto L) { self->HandleThread(th, L); });
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, p = std::move(p), caller, handler, th](auto L) mutable {
ljq->Push(self, [this, self, ljq, p = std::move(p), caller, handler, th](auto L) mutable {
auto thL = th->Init(L);
lua_rawgeti(thL, LUA_REGISTRYINDEX, handler->index());
if (p) {
lua_pushstring(thL, p->first.c_str());
nf7::luajit::PushValue(thL, p->second);
} else {
lua_pushnil(thL);
lua_pushnil(thL);
}
lua_pushstring(thL, p.first.c_str());
nf7::luajit::PushValue(thL, p.second);
PushCaller(thL, caller);
PushContextTable(thL);
PushContextTable(ljq, thL);
th->Resume(thL, 4);
});
} catch (nf7::Exception& e) {
log_->Error("failed to call handler: "+e.msg());
}
void HandleThread(nf7::luajit::Thread& th, lua_State* L) noexcept {
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(),
ljq->Push(shared_from_this(),
[th = th.shared_from_this(), L](auto) { th->Resume(L, 0); });
return;
@ -320,12 +276,16 @@ class Node::Lambda final : public nf7::Node::Lambda,
lua_setmetatable(L, -2);
}
void PushContextTable(lua_State* L) noexcept {
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);
const int idx = luaL_ref(L, LUA_REGISTRYINDEX);
ctxtable_.emplace(shared_from_this(), ljq_, idx);
ctxtable_.emplace(shared_from_this(), ljq, idx);
} else {
lua_rawgeti(L, LUA_REGISTRYINDEX, ctxtable_->index());
}
@ -337,21 +297,19 @@ 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 {
if (handler_) return handler_;
if (auto fetch = fetch_.lock()) return fetch->fu();
auto fetch = std::make_shared<FetchTask>(*this);
fetch->Start();
fetch_ = {fetch};
return fetch->fu();
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);
switch (ev.type) {
case Event::kAdd:
log_->SetUp(*this);
FetchHandler();
return;
case Event::kRemove:
@ -363,6 +321,8 @@ void Node::Handle(const Event& ev) noexcept {
}
}
void Node::Update() noexcept {
nf7::FileBase::Update();
const auto& style = ImGui::GetStyle();
const auto em = ImGui::GetFontSize();
@ -371,22 +331,21 @@ void Node::Update() noexcept {
}
if (ImGui::BeginPopup("ConfigPopup")) {
static std::string path;
static std::string desc;
static std::string in, out;
static std::vector<std::string> invec, outvec;
ImGui::TextUnformatted("LuaJIT/Node: config");
if (ImGui::IsWindowAppearing()) {
path = obj_.path().Stringify();
desc = desc;
Join(in, data().inputs);
Join(out, data().outputs);
}
obj_editor_.ButtonWithLabel("obj factory");
const auto w = ImGui::CalcItemWidth()/2 - style.ItemSpacing.x/2;
ImGui::InputText("path", &path);
ImGui::InputTextMultiline("description", &desc, {0, 4*em});
ImGui::BeginGroup();
ImGui::TextUnformatted("input:");
@ -401,16 +360,6 @@ void Node::Update() noexcept {
ImGui::TextUnformatted("sockets");
bool err = false;
File::Path p;
try {
p = File::Path::Parse(path);
ResolveOrThrow(p);
} catch (File::NotFoundException&) {
ImGui::Bullet(); ImGui::TextUnformatted("path seems to be missing");
} catch (nf7::Exception& e) {
ImGui::Bullet(); ImGui::Text("invalid path: %s", e.msg().c_str());
err = true;
}
try {
Split(invec, in);
} catch (nf7::Exception& e) {
@ -428,8 +377,7 @@ void Node::Update() noexcept {
ImGui::CloseCurrentPopup();
auto ctx = std::make_shared<nf7::GenericContext>(*this, "rebuilding node");
env().ExecMain(ctx, [&, p = std::move(p)]() mutable {
obj_ = std::move(p);
env().ExecMain(ctx, [&]() mutable {
data().desc = std::move(desc);
data().inputs = std::move(invec);
data().outputs = std::move(outvec);
@ -443,17 +391,19 @@ void Node::UpdateMenu() noexcept {
if (ImGui::MenuItem("config")) {
popup_ = "ConfigPopup";
}
obj_editor_.MenuWithTooltip("factory");
ImGui::Separator();
if (ImGui::MenuItem("try fetch handler")) {
FetchHandler();
}
if (ImGui::MenuItem("drop cached handler")) {
DropHandler();
}
}
void Node::UpdateTooltip() noexcept {
ImGui::Text("path : %s", obj_.path().Stringify().c_str());
ImGui::Text("handler: %s", handler_? "ready": "no");
ImGui::Text("src:");
ImGui::Indent();
obj_editor_.Tooltip();
ImGui::Unindent();
ImGui::Spacing();
ImGui::Text("input:");
@ -484,15 +434,6 @@ void Node::UpdateTooltip() noexcept {
ImGui::TextUnformatted(data().desc.c_str());
}
ImGui::Unindent();
ImGui::TextDisabled("drop a file here to set it as source");
}
void Node::UpdateDragDropTarget() noexcept {
if (auto p = gui::dnd::Accept<Path>(gui::dnd::kFilePath)) {
obj_ = std::move(*p);
}
}
void Node::UpdateNode(Node::Editor&) noexcept {
}
}

View File

@ -13,12 +13,15 @@
#include "common/async_buffer.hh"
#include "common/dir_item.hh"
#include "common/file_ref.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_dnd.hh"
#include "common/gui_file.hh"
#include "common/life.hh"
#include "common/lock.hh"
#include "common/luajit.hh"
#include "common/luajit_obj.hh"
@ -36,10 +39,10 @@ using namespace std::literals;
namespace nf7 {
namespace {
class Obj final : public nf7::File, public nf7::DirItem, public nf7::luajit::Obj {
class Obj final : public nf7::FileBase, public nf7::DirItem, public nf7::luajit::Obj {
public:
static inline const GenericTypeInfo<Obj> kType = {
"LuaJIT/Obj", {"nf7::DirItem",}};
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.");
@ -55,11 +58,24 @@ class Obj final : public nf7::File, public nf7::DirItem, public nf7::luajit::Obj
class ExecTask;
Obj(Env& env, Path&& path = {}) noexcept :
File(kType, env),
DirItem(DirItem::kTooltip | DirItem::kMenu | DirItem::kDragDropTarget),
struct Data final {
nf7::FileHolder::Tag src;
};
Obj(Env& env, const nf7::FileHolder* src = nullptr, Data&& = {}) noexcept :
nf7::FileBase(kType, env, {&src_, &src_editor_}),
nf7::DirItem(nf7::DirItem::kTooltip |
nf7::DirItem::kMenu),
life_(*this),
log_(std::make_shared<nf7::LoggerRef>()),
src_(*this, std::move(path)) {
src_(*this, "src", src),
src_editor_(src_, [](auto& t) { return t.flags().contains("nf7::AsyncBuffer"); }),
mem_({.src = {src_}}) {
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) {
@ -69,22 +85,23 @@ class Obj final : public nf7::File, public nf7::DirItem, public nf7::luajit::Obj
ar(src_);
}
std::unique_ptr<File> Clone(Env& env) const noexcept override {
return std::make_unique<Obj>(env, Path(src_.path()));
return std::make_unique<Obj>(env, &src_, Data {mem_.data()});
}
void Handle(const Event&) noexcept override;
void Update() noexcept override;
void UpdateMenu() noexcept override;
void UpdateTooltip() noexcept override;
void UpdateDragDropTarget() 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>(t).Select(this);
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_;
@ -92,19 +109,19 @@ class Obj final : public nf7::File, public nf7::DirItem, public nf7::luajit::Obj
nf7::Task<std::shared_ptr<nf7::luajit::Ref>>::Holder exec_;
const char* popup_ = nullptr;
nf7::FileHolder src_;
nf7::gui::FileHolderEditor src_editor_;
// persistent params
nf7::FileRef src_;
nf7::GenericMemento<Data> mem_;
void Reset() noexcept;
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_) {
Task(target.env(), target.id()), target_(&target), log_(target.log_) {
}
size_t GetMemoryUsage() const noexcept override {
@ -112,7 +129,8 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
}
private:
Obj* target_;
Obj* const target_;
std::shared_ptr<nf7::LoggerRef> log_;
std::string chunkname_;
@ -123,13 +141,14 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
nf7::Future<std::shared_ptr<nf7::luajit::Ref>>::Coro Proc() noexcept override {
try {
auto& srcf = *target_->src_;
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);
log_->Trace("source file lock acquired");
// get size of source
buf_size_ = co_await src->size();
@ -147,31 +166,26 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
throw nf7::Exception("failed to read all bytes from source");
}
// create thread to compile lua script
// 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");
}
if (auto str = lua_tostring(L, -1)) {
log_->Info("got '"s+str+"'");
} else {
log_->Info("got ["s+lua_typename(L, lua_type(L, -1))+"]");
}
return luaL_ref(L, LUA_REGISTRYINDEX);
});
// setup watcher
// start watcher on target_->watcher_
try {
*target_->src_; // check if the src is alive
auto& w = target_->watcher_;
w.emplace(env());
w->Watch(srcf.id());
w->Watch(srcf_id);
std::weak_ptr<Task> wself = self();
w->AddHandler(Event::kUpdate, [t = target_, wself](auto&) {
@ -203,10 +217,8 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
// wait for end of execution and return built object's index
const int idx = co_await lua_pro.future();
log_->Trace("task finished");
// context for object cache
// TODO use specific Context type
auto ctx = std::make_shared<nf7::GenericContext>(env(), initiator(), "luajit object cache");
// return the object and cache it
@ -214,7 +226,6 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
co_yield target_->cache_;
} catch (Exception& e) {
log_->Error(e.msg());
throw;
}
}
@ -239,7 +250,9 @@ class Obj::ExecTask final : public nf7::Task<std::shared_ptr<nf7::luajit::Ref>>
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_};
if (cache_) {
return std::shared_ptr<nf7::luajit::Ref>{cache_};
}
auto exec = std::make_shared<ExecTask>(*this);
exec->Start();
@ -247,14 +260,13 @@ nf7::Future<std::shared_ptr<nf7::luajit::Ref>> Obj::Build() noexcept {
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:
exec_ = {};
cache_ = nullptr;
watcher_ = std::nullopt;
DropCache();
log_->TearDown();
break;
@ -262,79 +274,25 @@ void Obj::Handle(const Event& ev) noexcept {
break;
}
}
void Obj::Reset() noexcept {
void Obj::DropCache() noexcept {
exec_ = {};
cache_ = nullptr;
watcher_ = std::nullopt;
}
void Obj::Update() noexcept {
if (const auto popup = std::exchange(popup_, nullptr)) {
ImGui::OpenPopup(popup);
}
if (ImGui::BeginPopup("ConfigPopup")) {
static std::string path_str;
ImGui::TextUnformatted("LuaJIT/Obj: config");
if (ImGui::IsWindowAppearing()) {
path_str = src_.path().Stringify();
}
const bool submit = ImGui::InputText(
"path", &path_str, ImGuiInputTextFlags_EnterReturnsTrue);
Path path;
bool err = false;
try {
path = Path::Parse(path_str);
} catch (Exception& e) {
ImGui::Bullet(); ImGui::Text("invalid path: %s", e.msg().c_str());
err = true;
}
try {
ResolveOrThrow(path);
} catch (File::NotFoundException&) {
ImGui::Bullet(); ImGui::Text("(target seems to be missing)");
}
if (!err) {
if (ImGui::Button("ok") || submit) {
ImGui::CloseCurrentPopup();
if (path != src_.path()) {
auto task = [this, p = std::move(path)]() mutable {
src_ = std::move(p);
Reset();
};
auto ctx = std::make_shared<
nf7::GenericContext>(*this, "changing source path");
env().ExecMain(ctx, std::move(task));
}
}
}
ImGui::EndPopup();
}
}
void Obj::UpdateMenu() noexcept {
if (ImGui::MenuItem("config")) {
popup_ = "ConfigPopup";
}
src_editor_.MenuWithTooltip("src");
ImGui::Separator();
if (ImGui::MenuItem("try build")) {
Build();
}
if (ImGui::MenuItem("drop cache", nullptr, nullptr, !!cache_)) {
Reset();
DropCache();
}
}
void Obj::UpdateTooltip() noexcept {
ImGui::Text("source: %s", src_.path().Stringify().c_str());
ImGui::Text("source: %s", src_editor_.GetDisplayText().c_str());
ImGui::Text("cache : %d", cache_? cache_->index(): -1);
ImGui::TextDisabled("drop a file here to set it as source");
}
void Obj::UpdateDragDropTarget() noexcept {
if (auto p = gui::dnd::Accept<Path>(gui::dnd::kFilePath)) {
src_ = std::move(*p);
}
}
}

View File

@ -72,7 +72,7 @@ class Adaptor final : public nf7::FileBase, public nf7::Sequencer {
};
Adaptor(Env& env, const nf7::FileHolder* target = nullptr, const Data* data = nullptr) noexcept :
nf7::FileBase(kType, env, {&target_}),
nf7::FileBase(kType, env, {&target_, &target_editor_}),
Sequencer(Sequencer::kCustomItem |
Sequencer::kTooltip |
Sequencer::kParamPanel),

View File

@ -43,7 +43,7 @@ class Call final : public nf7::FileBase, public nf7::Sequencer {
class SessionLambda;
Call(Env& env, const nf7::FileHolder* callee = nullptr, std::string_view expects = "") noexcept :
FileBase(kType, env, {&callee_}),
FileBase(kType, env, {&callee_, &callee_editor_}),
Sequencer(Sequencer::kCustomItem |
Sequencer::kTooltip |
Sequencer::kParamPanel),