nf7/common/node_root_lambda.hh

117 lines
3.0 KiB
C++

#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;
~NodeRootLambda() noexcept {
target_ = nullptr;
for (auto& pro : pro_) {
pro.second.Throw(std::make_exception_ptr(
nf7::Exception {"output was never satisified"}));
}
}
private:
std::shared_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) {
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