improve resilience to breaking changes of serialization format
This commit is contained in:
parent
8c25d22955
commit
231f67d5dd
@ -23,7 +23,6 @@ set(NF7_CXX_FLAGS
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
add_subdirectory(thirdparty EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(tool)
|
||||
|
||||
|
||||
# ---- application ----
|
||||
@ -40,6 +39,7 @@ target_compile_definitions(nf7
|
||||
)
|
||||
target_sources(nf7
|
||||
PRIVATE
|
||||
init.hh
|
||||
main.cc
|
||||
nf7.cc
|
||||
nf7.hh
|
||||
@ -135,14 +135,3 @@ target_link_libraries(nf7
|
||||
source_location
|
||||
yas
|
||||
)
|
||||
|
||||
# ---- resource compile ----
|
||||
set(NF7_DEFAULT_ROOT_INC "${NF7_GENERATED_INCLUDE_DIR}/root.nf7.inc")
|
||||
add_custom_command(
|
||||
OUTPUT ${NF7_DEFAULT_ROOT_INC}
|
||||
DEPENDS nf7-init
|
||||
COMMAND $<TARGET_FILE:nf7-init> > ${NF7_DEFAULT_ROOT_INC}
|
||||
COMMENT "generating root.nf7..."
|
||||
VERBATIM
|
||||
)
|
||||
target_sources(nf7 PRIVATE ${NF7_DEFAULT_ROOT_INC})
|
||||
|
@ -42,11 +42,16 @@ class FileHolder : public nf7::FileBase::Feature {
|
||||
FileHolder& operator=(const FileHolder&) = delete;
|
||||
FileHolder& operator=(FileHolder&&) = delete;
|
||||
|
||||
void Serialize(auto& ar) const {
|
||||
void Serialize(nf7::Serializer& ar) const {
|
||||
ar(entity_);
|
||||
}
|
||||
void Deserialize(auto& ar) {
|
||||
ar(entity_);
|
||||
void Deserialize(nf7::Deserializer& ar) {
|
||||
try {
|
||||
ar(entity_);
|
||||
} catch (nf7::Exception&) {
|
||||
entity_ = std::monostate {};
|
||||
ar.env().Throw(std::current_exception());
|
||||
}
|
||||
SetUp();
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
@ -21,20 +22,22 @@ concept GenericTypeInfo_Description_ = requires() { T::kTypeDescription; };
|
||||
|
||||
|
||||
template <typename T>
|
||||
class GenericTypeInfo : public File::TypeInfo {
|
||||
class GenericTypeInfo : public nf7::File::TypeInfo {
|
||||
public:
|
||||
GenericTypeInfo(const std::string& name, std::unordered_set<std::string>&& v) noexcept :
|
||||
TypeInfo(name, AddFlags(std::move(v))) {
|
||||
}
|
||||
|
||||
std::unique_ptr<File> Deserialize(Env& env, Deserializer& d) const override
|
||||
std::unique_ptr<nf7::File> Deserialize(nf7::Deserializer& ar) const override
|
||||
try {
|
||||
return std::make_unique<T>(env, d);
|
||||
return std::make_unique<T>(ar);
|
||||
} catch (nf7::Exception&) {
|
||||
throw nf7::DeserializeException {"deserialization failed"};
|
||||
} catch (std::exception&) {
|
||||
throw nf7::DeserializeException {"deserialization failed"};
|
||||
}
|
||||
std::unique_ptr<File> Create(Env& env) const override {
|
||||
if constexpr (std::is_constructible<T, Env&>::value) {
|
||||
std::unique_ptr<File> Create(nf7::Env& env) const override {
|
||||
if constexpr (std::is_constructible<T, nf7::Env&>::value) {
|
||||
return std::make_unique<T>(env);
|
||||
} else {
|
||||
throw nf7::Exception {name()+" has no factory without parameters"};
|
||||
@ -54,7 +57,7 @@ class GenericTypeInfo : public File::TypeInfo {
|
||||
private:
|
||||
static std::unordered_set<std::string> AddFlags(
|
||||
std::unordered_set<std::string>&& flags) noexcept {
|
||||
if (std::is_constructible<T, Env&>::value) {
|
||||
if (std::is_constructible<T, nf7::Env&>::value) {
|
||||
flags.insert("nf7::File::TypeInfo::Factory");
|
||||
}
|
||||
return flags;
|
||||
|
@ -20,7 +20,9 @@ struct serializer<
|
||||
public:
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const std::unique_ptr<nf7::File>& f) {
|
||||
ar(std::string(f->type().name()));
|
||||
ar(std::string {f->type().name()});
|
||||
|
||||
typename Archive::ChunkGuard guard {ar};
|
||||
f->Serialize(ar);
|
||||
return ar;
|
||||
}
|
||||
@ -28,7 +30,16 @@ struct serializer<
|
||||
static Archive& load(Archive& ar, std::unique_ptr<nf7::File>& f) {
|
||||
std::string name;
|
||||
ar(name);
|
||||
f = nf7::File::registry(name).Deserialize(nf7::Env::Peek(), ar);
|
||||
auto& type = nf7::File::registry(name);
|
||||
|
||||
try {
|
||||
typename Archive::ChunkGuard guard {ar};
|
||||
f = type.Deserialize(ar);
|
||||
guard.ValidateEnd();
|
||||
} catch (...) {
|
||||
f = nullptr;
|
||||
throw;
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
|
@ -32,13 +32,13 @@ class AudioContext final : public nf7::File, public nf7::DirItem {
|
||||
|
||||
class Queue;
|
||||
|
||||
AudioContext(Env&) noexcept;
|
||||
AudioContext(nf7::Env&) noexcept;
|
||||
|
||||
AudioContext(Env& env, Deserializer&) noexcept : AudioContext(env) {
|
||||
AudioContext(nf7::Deserializer& ar) noexcept : AudioContext(ar.env()) {
|
||||
}
|
||||
void Serialize(Serializer&) const noexcept override {
|
||||
void Serialize(nf7::Serializer&) const noexcept override {
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<AudioContext>(env);
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ class AudioContext final : public nf7::File, public nf7::DirItem {
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateTooltip() noexcept override;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<
|
||||
nf7::DirItem, nf7::audio::Queue>(t).Select(this, q_.get());
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class Device final : public nf7::FileBase, public nf7::DirItem, public nf7::Node
|
||||
nf7::FileBase::Install(data_->log);
|
||||
}
|
||||
|
||||
Device(nf7::Env& env, nf7::Deserializer& ar) : Device(env) {
|
||||
Device(nf7::Deserializer& ar) : Device(ar.env()) {
|
||||
ar(selector_, cfg_);
|
||||
}
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
|
@ -33,12 +33,12 @@ class LuaContext final : public nf7::File, public nf7::DirItem {
|
||||
|
||||
class Queue;
|
||||
|
||||
LuaContext(Env& env) :
|
||||
LuaContext(nf7::Env& env) :
|
||||
File(kType, env), DirItem(DirItem::kTooltip) {
|
||||
q_ = std::make_shared<Queue>(*this);
|
||||
}
|
||||
|
||||
LuaContext(Env& env, Deserializer&) : LuaContext(env) {
|
||||
LuaContext(nf7::Deserializer& ar) : LuaContext(ar.env()) {
|
||||
}
|
||||
void Serialize(Serializer&) const noexcept override {
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ class InlineNode final : public nf7::FileBase, public nf7::DirItem, public nf7::
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
InlineNode(nf7::Env& env, nf7::Deserializer& ar) : InlineNode(env) {
|
||||
InlineNode(nf7::Deserializer& ar) : InlineNode(ar.env()) {
|
||||
ar(data().script);
|
||||
}
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
|
@ -97,16 +97,16 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Node(Env& env, Deserializer& ar) : Node(env) {
|
||||
Node(nf7::Deserializer& ar) : Node(ar.env()) {
|
||||
ar(obj_, data().desc, data().inputs, data().outputs);
|
||||
|
||||
nf7::util::Uniq(data().inputs);
|
||||
nf7::util::Uniq(data().outputs);
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(obj_, data().desc, data().inputs, data().outputs);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<Node>(env, Data {data()});
|
||||
}
|
||||
|
||||
@ -123,7 +123,7 @@ class Node final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
void UpdateTooltip() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<
|
||||
nf7::DirItem, nf7::Memento, nf7::Node>(t).Select(this, &mem_);
|
||||
}
|
||||
|
@ -51,10 +51,10 @@ class Imm final : public nf7::File, public nf7::DirItem, public nf7::Node {
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Imm(nf7::Env& env, Deserializer& ar) : Imm(env) {
|
||||
Imm(nf7::Deserializer& ar) : Imm(ar.env()) {
|
||||
ar(mem_.data());
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(mem_.data());
|
||||
}
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
|
@ -72,10 +72,10 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
using ItemId = uint64_t;
|
||||
using ItemList = std::vector<std::unique_ptr<Item>>;
|
||||
|
||||
Network(Env& env,
|
||||
const gui::Window* win = nullptr,
|
||||
ItemList&& items = {},
|
||||
NodeLinkStore&& links = {}) :
|
||||
Network(nf7::Env& env,
|
||||
const gui::Window* win = nullptr,
|
||||
ItemList&& items = {},
|
||||
nf7::NodeLinkStore&& links = {}) :
|
||||
nf7::FileBase(kType, env, {&add_popup_, &socket_popup_}),
|
||||
nf7::DirItem(nf7::DirItem::kMenu |
|
||||
nf7::DirItem::kTooltip |
|
||||
@ -93,14 +93,14 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
history_.Clear();
|
||||
}
|
||||
|
||||
Network(Env& env, Deserializer& ar) : Network(env) {
|
||||
ar(win_, items_, links_, canvas_, inputs_, outputs_);
|
||||
Network(nf7::Deserializer& ar) : Network(ar.env()) {
|
||||
ar(win_, links_, canvas_, inputs_, outputs_, items_);
|
||||
Sanitize();
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
ar(win_, items_, links_, canvas_, inputs_, outputs_);
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(win_, links_, canvas_, inputs_, outputs_, items_);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<File> Clone(nf7::Env& env) const noexcept override {
|
||||
ItemList items;
|
||||
items.reserve(items_.size());
|
||||
for (const auto& item : items_) {
|
||||
@ -120,8 +120,8 @@ class Network final : public nf7::FileBase, public nf7::DirItem, public nf7::Nod
|
||||
void UpdateWidget() noexcept override;
|
||||
void UpdateNode(Node::Editor&) noexcept override;
|
||||
|
||||
std::shared_ptr<Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<Node::Lambda>&) noexcept override;
|
||||
std::shared_ptr<nf7::Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<nf7::Node::Lambda>&) noexcept override;
|
||||
|
||||
std::span<const std::string> GetInputs() const noexcept override {
|
||||
return inputs_;
|
||||
@ -266,7 +266,7 @@ class Network::Item final {
|
||||
id_(id), file_(std::move(file)) {
|
||||
Initialize();
|
||||
}
|
||||
Item(Env& env, const Item& src) noexcept :
|
||||
Item(nf7::Env& env, const Item& src) noexcept :
|
||||
id_(src.id_), file_(src.file_->Clone(env)), pos_(src.pos_), select_(src.select_) {
|
||||
Initialize();
|
||||
}
|
||||
@ -276,13 +276,13 @@ class Network::Item final {
|
||||
|
||||
explicit Item(Deserializer& ar)
|
||||
try {
|
||||
ar(id_, file_, pos_, select_);
|
||||
ar(id_, pos_, select_, file_);
|
||||
Initialize();
|
||||
} catch (std::exception&) {
|
||||
throw DeserializeException("failed to deserialize Node/Network item");
|
||||
}
|
||||
void Serialize(Serializer& ar) {
|
||||
ar(id_, file_, pos_, select_);
|
||||
ar(id_, pos_, select_, file_);
|
||||
}
|
||||
|
||||
void Attach(Network& owner) noexcept;
|
||||
@ -703,11 +703,11 @@ class Network::Initiator final : public nf7::File,
|
||||
Initiator(nf7::Env& env) noexcept : File(kType, env) {
|
||||
}
|
||||
|
||||
Initiator(nf7::Env& env, Deserializer&) : Initiator(env) {
|
||||
Initiator(nf7::Deserializer& ar) : Initiator(ar.env()) {
|
||||
}
|
||||
void Serialize(Serializer&) const noexcept override {
|
||||
void Serialize(nf7::Serializer&) const noexcept override {
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<Initiator>(env);
|
||||
}
|
||||
|
||||
@ -741,7 +741,7 @@ class Network::Initiator final : public nf7::File,
|
||||
InternalNode::Flags flags() const noexcept override {
|
||||
return InternalNode::kInputHandler;
|
||||
}
|
||||
File::Interface* interface(const std::type_info& t) noexcept {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept {
|
||||
return nf7::InterfaceSelector<nf7::Node>(t).Select(this);
|
||||
}
|
||||
};
|
||||
@ -760,17 +760,17 @@ class Network::Terminal : public nf7::File,
|
||||
std::string name;
|
||||
};
|
||||
|
||||
Terminal(Env& env, Data&& data = {}) noexcept :
|
||||
Terminal(nf7::Env& env, Data&& data = {}) noexcept :
|
||||
nf7::File(kType, env),
|
||||
life_(*this), mem_(std::move(data)) {
|
||||
mem_.onRestore = [this]() { Touch(); };
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Terminal(nf7::Env& env, Deserializer& ar) : Terminal(env) {
|
||||
Terminal(nf7::Deserializer& ar) : Terminal(ar.env()) {
|
||||
ar(data().type, data().name);
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(data().type, data().name);
|
||||
}
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
@ -1323,7 +1323,40 @@ struct serializer<
|
||||
}
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, std::unique_ptr<nf7::Network::Item>& item) {
|
||||
item = std::make_unique<nf7::Network::Item>(ar);
|
||||
try {
|
||||
item = std::make_unique<nf7::Network::Item>(ar);
|
||||
} catch (nf7::Exception&) {
|
||||
item = nullptr;
|
||||
ar.env().Throw(std::current_exception());
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t F>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
std::vector<std::unique_ptr<nf7::Network::Item>>> {
|
||||
public:
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const std::vector<std::unique_ptr<nf7::Network::Item>>& v) {
|
||||
ar(static_cast<uint64_t>(v.size()));
|
||||
for (auto& item : v) {
|
||||
ar(item);
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, std::vector<std::unique_ptr<nf7::Network::Item>>& v) {
|
||||
uint64_t size;
|
||||
ar(size);
|
||||
v.resize(size);
|
||||
for (auto& item : v) {
|
||||
ar(item);
|
||||
}
|
||||
v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
|
@ -54,7 +54,7 @@ class Ref final : public nf7::FileBase, public nf7::Node {
|
||||
std::vector<std::string> outputs;
|
||||
};
|
||||
|
||||
Ref(Env& env, Data&& data = {}) noexcept :
|
||||
Ref(nf7::Env& env, Data&& data = {}) noexcept :
|
||||
nf7::FileBase(kType, env),
|
||||
life_(*this),
|
||||
log_(std::make_shared<nf7::LoggerRef>(*this)),
|
||||
@ -65,18 +65,18 @@ class Ref final : public nf7::FileBase, public nf7::Node {
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Ref(Env& env, Deserializer& ar) : Ref(env) {
|
||||
Ref(nf7::Deserializer& ar) : Ref(ar.env()) {
|
||||
ar(data().target, data().inputs, data().outputs);
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(data().target, data().inputs, data().outputs);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<Ref>(env, Data {data()});
|
||||
}
|
||||
|
||||
std::shared_ptr<Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<Node::Lambda>&) noexcept override;
|
||||
std::shared_ptr<nf7::Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<nf7::Node::Lambda>&) noexcept override;
|
||||
std::span<const std::string> GetInputs() const noexcept override {
|
||||
return data().inputs;
|
||||
}
|
||||
@ -85,9 +85,9 @@ class Ref final : public nf7::FileBase, public nf7::Node {
|
||||
}
|
||||
|
||||
void Update() noexcept override;
|
||||
void UpdateNode(Node::Editor&) noexcept override;
|
||||
void UpdateNode(nf7::Node::Editor&) noexcept override;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<nf7::Memento, nf7::Node>(t).Select(this, &mem_);
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ class Adaptor final : public nf7::FileBase, public nf7::Sequencer {
|
||||
std::vector<std::pair<std::string, std::string>> output_map;
|
||||
};
|
||||
|
||||
Adaptor(Env& env, Data&& data = {}) noexcept :
|
||||
Adaptor(nf7::Env& env, Data&& data = {}) noexcept :
|
||||
nf7::FileBase(kType, env, {&target_, &target_editor_}),
|
||||
Sequencer(Sequencer::kCustomItem |
|
||||
Sequencer::kTooltip |
|
||||
@ -83,25 +83,25 @@ class Adaptor final : public nf7::FileBase, public nf7::Sequencer {
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Adaptor(Env& env, Deserializer& ar) : Adaptor(env) {
|
||||
Adaptor(nf7::Deserializer& ar) : Adaptor(ar.env()) {
|
||||
ar(target_, data().input_imm, data().input_map, data().output_map);
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(target_, data().input_imm, data().input_map, data().output_map);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<Adaptor>(env, Data {data()});
|
||||
}
|
||||
|
||||
std::shared_ptr<Sequencer::Lambda> CreateLambda(
|
||||
std::shared_ptr<nf7::Sequencer::Lambda> CreateLambda(
|
||||
const std::shared_ptr<nf7::Context>&) noexcept override;
|
||||
|
||||
void UpdateItem(Sequencer::Editor&) noexcept override;
|
||||
void UpdateParamPanel(Sequencer::Editor&) noexcept override;
|
||||
void UpdateTooltip(Sequencer::Editor&) noexcept override;
|
||||
void UpdateItem(nf7::Sequencer::Editor&) noexcept override;
|
||||
void UpdateParamPanel(nf7::Sequencer::Editor&) noexcept override;
|
||||
void UpdateTooltip(nf7::Sequencer::Editor&) noexcept override;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return InterfaceSelector<
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<
|
||||
nf7::Memento, nf7::Sequencer>(t).Select(this, &mem_);
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ class Call final : public nf7::FileBase, public nf7::Sequencer {
|
||||
bool pure;
|
||||
};
|
||||
|
||||
Call(Env& env, Data&& data = {}) noexcept :
|
||||
Call(nf7::Env& env, Data&& data = {}) noexcept :
|
||||
FileBase(kType, env, {&callee_, &callee_editor_}),
|
||||
Sequencer(Sequencer::kCustomItem |
|
||||
Sequencer::kTooltip |
|
||||
@ -68,24 +68,24 @@ class Call final : public nf7::FileBase, public nf7::Sequencer {
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Call(Env& env, Deserializer& ar) : Call(env) {
|
||||
Call(nf7::Deserializer& ar) : Call(ar.env()) {
|
||||
ar(callee_, data().expects, data().pure);
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(callee_, data().expects, data().pure);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<Call>(env, Data {data()});
|
||||
}
|
||||
|
||||
std::shared_ptr<Sequencer::Lambda> CreateLambda(
|
||||
std::shared_ptr<nf7::Sequencer::Lambda> CreateLambda(
|
||||
const std::shared_ptr<nf7::Context>&) noexcept override;
|
||||
|
||||
void UpdateItem(Sequencer::Editor&) noexcept override;
|
||||
void UpdateParamPanel(Sequencer::Editor&) noexcept override;
|
||||
void UpdateTooltip(Sequencer::Editor&) noexcept override;
|
||||
void UpdateItem(nf7::Sequencer::Editor&) noexcept override;
|
||||
void UpdateParamPanel(nf7::Sequencer::Editor&) noexcept override;
|
||||
void UpdateTooltip(nf7::Sequencer::Editor&) noexcept override;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return InterfaceSelector<
|
||||
nf7::Memento, nf7::Sequencer>(t).Select(this, &mem_);
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class TL final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
|
||||
using ItemId = uint64_t;
|
||||
|
||||
TL(Env& env,
|
||||
TL(nf7::Env& env,
|
||||
std::vector<std::unique_ptr<Layer>>&& layers = {},
|
||||
ItemId next = 1,
|
||||
const nf7::gui::Window* win = nullptr) noexcept :
|
||||
@ -87,18 +87,18 @@ class TL final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
history_.Clear();
|
||||
}
|
||||
|
||||
TL(Env& env, Deserializer& ar) : TL(env) {
|
||||
ar(layers_, seq_inputs_, seq_outputs_, win_, tl_);
|
||||
TL(nf7::Deserializer& ar) : TL(ar.env()) {
|
||||
ar(seq_inputs_, seq_outputs_, win_, tl_, layers_);
|
||||
AssignId();
|
||||
ApplySeqSocketChanges();
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
ar(layers_, seq_inputs_, seq_outputs_, win_, tl_);
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(seq_inputs_, seq_outputs_, win_, tl_, layers_);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override;
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override;
|
||||
|
||||
std::shared_ptr<Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<Node::Lambda>&) noexcept override;
|
||||
std::shared_ptr<nf7::Node::Lambda> CreateLambda(
|
||||
const std::shared_ptr<nf7::Node::Lambda>&) noexcept override;
|
||||
std::span<const std::string> GetInputs() const noexcept override {
|
||||
return inputs_;
|
||||
}
|
||||
@ -106,7 +106,7 @@ class TL final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
return outputs_;
|
||||
}
|
||||
|
||||
void Handle(const Event& ev) noexcept;
|
||||
void Handle(const nf7::File::Event& ev) noexcept;
|
||||
void Update() noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateWidget() noexcept override;
|
||||
@ -117,7 +117,7 @@ class TL final : public nf7::FileBase, public nf7::DirItem, public nf7::Node {
|
||||
|
||||
void UpdateParamPanelWindow() noexcept;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return nf7::InterfaceSelector<nf7::DirItem, nf7::Node>(t).Select(this);
|
||||
}
|
||||
|
||||
@ -281,13 +281,13 @@ class TL::Item final : nf7::Env::Watcher {
|
||||
Item& operator=(Item&&) = delete;
|
||||
|
||||
void Save(auto& ar) {
|
||||
ar(id_, file_, timing_);
|
||||
ar(id_, timing_, file_);
|
||||
}
|
||||
static std::unique_ptr<TL::Item> Load(auto& ar) noexcept {
|
||||
static std::unique_ptr<TL::Item> Load(auto& ar) {
|
||||
ItemId id;
|
||||
std::unique_ptr<nf7::File> file;
|
||||
Timing timing;
|
||||
ar(id, file, timing);
|
||||
ar(id, timing, file);
|
||||
return std::make_unique<TL::Item>(id, std::move(file), timing);
|
||||
}
|
||||
std::unique_ptr<TL::Item> Clone(nf7::Env& env, ItemId id) const {
|
||||
@ -396,7 +396,7 @@ class TL::Layer final {
|
||||
void Save(auto& ar) {
|
||||
ar(items_, enabled_, height_);
|
||||
}
|
||||
static std::unique_ptr<TL::Layer> Load(auto& ar) noexcept {
|
||||
static std::unique_ptr<TL::Layer> Load(auto& ar) {
|
||||
std::vector<std::unique_ptr<nf7::TL::Item>> items;
|
||||
bool enabled;
|
||||
float height;
|
||||
@ -1645,7 +1645,40 @@ struct serializer<
|
||||
}
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, std::unique_ptr<nf7::TL::Item>& item) {
|
||||
item = nf7::TL::Item::Load(ar);
|
||||
try {
|
||||
item = nf7::TL::Item::Load(ar);
|
||||
} catch (nf7::Exception&) {
|
||||
item = nullptr;
|
||||
ar.env().Throw(std::current_exception());
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
|
||||
template <size_t F>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
std::vector<std::unique_ptr<nf7::TL::Item>>> {
|
||||
public:
|
||||
template <typename Archive>
|
||||
static Archive& save(Archive& ar, const std::vector<std::unique_ptr<nf7::TL::Item>>& v) {
|
||||
ar(static_cast<uint64_t>(v.size()));
|
||||
for (auto& item : v) {
|
||||
ar(item);
|
||||
}
|
||||
return ar;
|
||||
}
|
||||
template <typename Archive>
|
||||
static Archive& load(Archive& ar, std::vector<std::unique_ptr<nf7::TL::Item>>& v) {
|
||||
uint64_t size;
|
||||
ar(size);
|
||||
v.resize(size);
|
||||
for (auto& item : v) {
|
||||
ar(item);
|
||||
}
|
||||
v.erase(std::remove(v.begin(), v.end(), nullptr), v.end());
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <imgui_internal.h>
|
||||
#include <imgui_stdlib.h>
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/std/map.hpp>
|
||||
#include <yas/types/std/unordered_set.hpp>
|
||||
#include <yas/types/std/string.hpp>
|
||||
|
||||
@ -39,7 +38,7 @@ class Dir final : public nf7::FileBase,
|
||||
|
||||
using ItemMap = std::map<std::string, std::unique_ptr<File>>;
|
||||
|
||||
Dir(Env& env, ItemMap&& items = {}, const gui::Window* src = nullptr) noexcept :
|
||||
Dir(nf7::Env& env, ItemMap&& items = {}, const gui::Window* src = nullptr) noexcept :
|
||||
nf7::FileBase(kType, env, {&widget_popup_, &add_popup_, &rename_popup_}),
|
||||
nf7::DirItem(nf7::DirItem::kTree |
|
||||
nf7::DirItem::kMenu |
|
||||
@ -49,13 +48,33 @@ class Dir final : public nf7::FileBase,
|
||||
widget_popup_(*this), add_popup_(*this), rename_popup_(*this) {
|
||||
}
|
||||
|
||||
Dir(Env& env, Deserializer& ar) : Dir(env) {
|
||||
ar(items_, opened_, win_);
|
||||
Dir(nf7::Deserializer& ar) : Dir(ar.env()) {
|
||||
ar(opened_, win_);
|
||||
|
||||
uint64_t size;
|
||||
ar(size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
std::string name;
|
||||
ar(name);
|
||||
|
||||
std::unique_ptr<nf7::File> f;
|
||||
try {
|
||||
ar(f);
|
||||
items_[name] = std::move(f);
|
||||
} catch (nf7::Exception& e) {
|
||||
env().Throw(std::current_exception());
|
||||
}
|
||||
}
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
ar(items_, opened_, win_);
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(opened_, win_);
|
||||
|
||||
ar(static_cast<uint64_t>(items_.size()));
|
||||
for (auto& p : items_) {
|
||||
ar(p.first, p.second);
|
||||
}
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
ItemMap items;
|
||||
for (const auto& item : items_) {
|
||||
items[item.first] = item.second->Clone(env);
|
||||
@ -99,6 +118,10 @@ class Dir final : public nf7::FileBase,
|
||||
nf7::FileBase::Handle(ev);
|
||||
switch (ev.type) {
|
||||
case Event::kAdd:
|
||||
// force to show window if this is the root
|
||||
if (name() == "$") {
|
||||
win_.shown() = true;
|
||||
}
|
||||
for (const auto& item : items_) item.second->MoveUnder(*this, item.first);
|
||||
break;
|
||||
case Event::kRemove:
|
||||
|
@ -31,7 +31,7 @@ class ImGui_ final : public nf7::File, public nf7::DirItem {
|
||||
ImGui_(nf7::Env& env) noexcept :
|
||||
nf7::File(kType, env), nf7::DirItem(nf7::DirItem::kNone) {
|
||||
}
|
||||
ImGui_(nf7::Env& env, Deserializer& ar) noexcept : ImGui_(env) {
|
||||
ImGui_(nf7::Deserializer& ar) : ImGui_(ar.env()) {
|
||||
std::string config;
|
||||
ar(config);
|
||||
|
||||
@ -39,7 +39,7 @@ class ImGui_ final : public nf7::File, public nf7::DirItem {
|
||||
ImGui::LoadIniSettingsFromMemory(config.data(), config.size());
|
||||
}
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
size_t n;
|
||||
const char* config = ImGui::SaveIniSettingsToMemory(&n);
|
||||
ar(std::string_view(config, n));
|
||||
|
@ -69,34 +69,34 @@ class Logger final : public nf7::File,
|
||||
};
|
||||
class ItemStore;
|
||||
|
||||
Logger(Env& env, uint32_t max_rows = 1024, bool propagate = false, bool freeze = false) noexcept :
|
||||
Logger(nf7::Env& env, uint32_t max_rows = 1024, bool propagate = false, bool freeze = false) noexcept :
|
||||
File(kType, env), DirItem(DirItem::kMenu),
|
||||
param_(std::make_shared<Param>(max_rows, propagate, freeze)),
|
||||
win_(*this, "LogView") {
|
||||
win_.shown() = true;
|
||||
}
|
||||
|
||||
Logger(Env& env, Deserializer& ar) : Logger(env) {
|
||||
Logger(nf7::Deserializer& ar) : Logger(ar.env()) {
|
||||
ar(win_, param_->max_rows, param_->propagate, param_->freeze);
|
||||
|
||||
if (param_->max_rows == 0) {
|
||||
throw DeserializeException("max_rows must be 1 or more");
|
||||
}
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(win_, param_->max_rows, param_->propagate, param_->freeze);
|
||||
}
|
||||
std::unique_ptr<File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<Logger>(
|
||||
env, param_->max_rows, param_->propagate, param_->freeze);
|
||||
}
|
||||
|
||||
void Handle(const Event& ev) noexcept override;
|
||||
void Handle(const nf7::File::Event& ev) noexcept override;
|
||||
void Update() noexcept override;
|
||||
void UpdateMenu() noexcept override;
|
||||
void UpdateRowMenu(const Row&) noexcept;
|
||||
|
||||
File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
nf7::File::Interface* interface(const std::type_info& t) noexcept override {
|
||||
return InterfaceSelector<nf7::DirItem, nf7::Logger>(t).
|
||||
Select(this, store_.get());
|
||||
}
|
||||
|
@ -95,13 +95,13 @@ class NativeFile final : public nf7::FileBase,
|
||||
mem_.onCommit = [this]() { Refresh(); Touch(); };
|
||||
}
|
||||
|
||||
NativeFile(nf7::Env& env, nf7::Deserializer& ar) : NativeFile(env) {
|
||||
NativeFile(nf7::Deserializer& ar) : NativeFile(ar.env()) {
|
||||
ar(data().npath, data().mode);
|
||||
}
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(data().npath, data().mode);
|
||||
}
|
||||
std::unique_ptr<nf7::File> Clone(Env& env) const noexcept override {
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
return std::make_unique<NativeFile>(env, Data {data()});
|
||||
}
|
||||
|
||||
|
@ -78,12 +78,12 @@ class Curve final : public nf7::File,
|
||||
mem_.onCommit = [this]() { Touch(); };
|
||||
}
|
||||
|
||||
Curve(nf7::Env& env, Deserializer& ar) : Curve(env) {
|
||||
Curve(nf7::Deserializer& ar) : Curve(ar.env()) {
|
||||
ar(mem_.data());
|
||||
AssignId();
|
||||
Sanitize();
|
||||
}
|
||||
void Serialize(Serializer& ar) const noexcept override {
|
||||
void Serialize(nf7::Serializer& ar) const noexcept override {
|
||||
ar(mem_.data());
|
||||
}
|
||||
std::unique_ptr<nf7::File> Clone(nf7::Env& env) const noexcept override {
|
||||
|
19
init.hh
Normal file
19
init.hh
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "nf7.hh"
|
||||
|
||||
#include "common/dir.hh"
|
||||
|
||||
|
||||
inline std::unique_ptr<nf7::File> CreateRoot(nf7::Env& env) noexcept {
|
||||
auto ret = nf7::File::registry("System/Dir").Create(env);
|
||||
auto& dir = ret->interfaceOrThrow<nf7::Dir>();
|
||||
|
||||
dir.Add("_audio", nf7::File::registry("Audio/Context").Create(env));
|
||||
dir.Add("_imgui", nf7::File::registry("System/ImGui").Create(env));
|
||||
dir.Add("_logger", nf7::File::registry("System/Logger").Create(env));
|
||||
dir.Add("_luajit", nf7::File::registry("LuaJIT/Context").Create(env));
|
||||
|
||||
dir.Add("home", nf7::File::registry("System/Dir").Create(env));
|
||||
return ret;
|
||||
}
|
43
main.cc
43
main.cc
@ -24,22 +24,18 @@
|
||||
// Include glfw lastly to prevent conflict with windows.h.
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "init.hh"
|
||||
|
||||
|
||||
using namespace nf7;
|
||||
using namespace std::literals;
|
||||
|
||||
class Env final : public nf7::Env {
|
||||
public:
|
||||
static constexpr auto kFileName = "root.nf7";
|
||||
static constexpr char kDefaultRoot[] = {
|
||||
# include "generated/root.nf7.inc"
|
||||
};
|
||||
|
||||
static constexpr auto kFileName = "root.nf7";
|
||||
static constexpr size_t kSubTaskUnit = 64;
|
||||
|
||||
Env() noexcept : nf7::Env(std::filesystem::current_path()) {
|
||||
::Env::Push(*this);
|
||||
|
||||
// start threads
|
||||
main_thread_ = std::thread([this]() { MainThread(); });
|
||||
async_threads_.resize(std::max<size_t>(std::thread::hardware_concurrency(), 2));
|
||||
@ -48,22 +44,16 @@ class Env final : public nf7::Env {
|
||||
}
|
||||
|
||||
// deserialize
|
||||
try {
|
||||
if (!std::filesystem::exists(kFileName)) {
|
||||
std::ofstream of(kFileName, std::ios::binary);
|
||||
if (!of) throw Exception("failed to open native file: "s+kFileName);
|
||||
of.write(kDefaultRoot, sizeof(kDefaultRoot));
|
||||
of.flush();
|
||||
if (!of) throw Exception("failed to write to native file: "s+kFileName);
|
||||
}
|
||||
if (!std::filesystem::exists(kFileName)) {
|
||||
root_ = CreateRoot(*this);
|
||||
root_->MakeAsRoot();
|
||||
} else {
|
||||
try {
|
||||
yas::load<yas::file|yas::binary>("root.nf7", root_);
|
||||
nf7::Deserializer::Load(*this, kFileName, root_);
|
||||
root_->MakeAsRoot();
|
||||
} catch (std::exception& e) {
|
||||
throw Exception("failed to read: "s+kFileName+" ("+e.what()+")");
|
||||
} catch (nf7::Exception&) {
|
||||
Panic();
|
||||
}
|
||||
} catch (Exception&) {
|
||||
Panic();
|
||||
}
|
||||
}
|
||||
~Env() noexcept {
|
||||
@ -81,8 +71,6 @@ class Env final : public nf7::Env {
|
||||
|
||||
async_.Notify();
|
||||
for (auto& th : async_threads_) th.join();
|
||||
|
||||
::Env::Pop();
|
||||
}
|
||||
|
||||
void ExecMain(const std::shared_ptr<Context>& ctx, Task&& task) noexcept override {
|
||||
@ -112,9 +100,14 @@ class Env final : public nf7::Env {
|
||||
}
|
||||
|
||||
void Save() noexcept override {
|
||||
yas::file_ostream os(kFileName, yas::file_trunc);
|
||||
yas::binary_oarchive<yas::file_ostream, yas::binary> oa(os);
|
||||
oa & root_;
|
||||
try {
|
||||
nf7::Serializer::Save(kFileName, root_);
|
||||
} catch (nf7::Exception&) {
|
||||
Panic();
|
||||
}
|
||||
}
|
||||
void Throw(std::exception_ptr&& eptr) noexcept override {
|
||||
Panic(std::move(eptr));
|
||||
}
|
||||
|
||||
void Update() noexcept {
|
||||
|
71
nf7.cc
71
nf7.cc
@ -18,8 +18,6 @@ using namespace std::literals;
|
||||
|
||||
namespace nf7 {
|
||||
|
||||
static std::vector<Env*> env_stack_;
|
||||
|
||||
// static variable in function ensures that entity is initialized before using
|
||||
static inline auto& registry_() noexcept {
|
||||
static std::map<std::string, const File::TypeInfo*> registry_;
|
||||
@ -246,16 +244,6 @@ Context::Context(Env& env, File::Id initiator, const std::shared_ptr<Context>& p
|
||||
Context::~Context() noexcept {
|
||||
}
|
||||
|
||||
void Env::Push(Env& env) noexcept {
|
||||
env_stack_.push_back(&env);
|
||||
}
|
||||
Env& Env::Peek() noexcept {
|
||||
return *env_stack_.back();
|
||||
}
|
||||
void Env::Pop() noexcept {
|
||||
env_stack_.pop_back();
|
||||
}
|
||||
|
||||
File& Env::GetFileOrThrow(File::Id id) const {
|
||||
if (auto ret = GetFile(id)) return *ret;
|
||||
throw ExpiredException("file ("+std::to_string(id)+") is expired");
|
||||
@ -274,4 +262,63 @@ void Env::Watcher::Watch(File::Id id) noexcept {
|
||||
env_->AddWatcher(id, *this);
|
||||
}
|
||||
|
||||
|
||||
SerializerStream::SerializerStream(const char* path, const char* mode) :
|
||||
fp_(std::fopen(path, mode)), off_(0) {
|
||||
if (!fp_) {
|
||||
throw nf7::Exception {"failed to open file: "+std::string {path}};
|
||||
}
|
||||
|
||||
if (0 != std::fseek(fp_, 0, SEEK_END)) {
|
||||
throw nf7::Exception {"failed to seek file: "+std::string {path}};
|
||||
}
|
||||
size_ = static_cast<size_t>(std::ftell(fp_));
|
||||
if (0 != std::fseek(fp_, 0, SEEK_SET)) {
|
||||
throw nf7::Exception {"failed to seek file: "+std::string {path}};
|
||||
}
|
||||
}
|
||||
|
||||
Serializer::ChunkGuard::ChunkGuard(nf7::Serializer& ar) : ar_(&ar) {
|
||||
ar_->st_->Seek(ar_->st_->offset()+sizeof(uint64_t));
|
||||
begin_ = ar_->st_->offset();
|
||||
}
|
||||
Serializer::ChunkGuard::~ChunkGuard() noexcept {
|
||||
try {
|
||||
const auto end = ar_->st_->offset();
|
||||
ar_->st_->Seek(begin_-sizeof(uint64_t));
|
||||
*ar_ & static_cast<uint64_t>(end - begin_);
|
||||
ar_->st_->Seek(end);
|
||||
} catch (nf7::Exception&) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
Deserializer::ChunkGuard::ChunkGuard(nf7::Deserializer& ar) : ar_(&ar) {
|
||||
*ar_ & expect_;
|
||||
begin_ = ar_->st_->offset();
|
||||
}
|
||||
Deserializer::ChunkGuard::ChunkGuard(nf7::Deserializer& ar, nf7::Env& env) :
|
||||
ChunkGuard(ar) {
|
||||
env_prev_ = ar_->env_;
|
||||
ar_->env_ = &env;
|
||||
}
|
||||
Deserializer::ChunkGuard::~ChunkGuard() {
|
||||
try {
|
||||
if (env_prev_) {
|
||||
ar_->env_ = env_prev_;
|
||||
}
|
||||
const auto end = begin_ + expect_;
|
||||
if (ar_->st_->offset() != end) {
|
||||
ar_->st_->Seek(end);
|
||||
}
|
||||
} catch (nf7::Exception&) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
void Deserializer::ChunkGuard::ValidateEnd() {
|
||||
if (begin_+expect_ != ar_->st_->offset()) {
|
||||
throw nf7::DeserializeException {"invalid chunk size"};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nf7
|
||||
|
181
nf7.hh
181
nf7.hh
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
@ -25,8 +26,9 @@ class File;
|
||||
class Context;
|
||||
class Env;
|
||||
|
||||
using Serializer = yas::binary_oarchive<yas::file_ostream, yas::binary>;
|
||||
using Deserializer = yas::binary_iarchive<yas::file_istream, yas::binary>;
|
||||
class SerializerStream;
|
||||
class Serializer;
|
||||
class Deserializer;
|
||||
|
||||
class Exception : public std::nested_exception {
|
||||
public:
|
||||
@ -157,7 +159,7 @@ class File::TypeInfo {
|
||||
TypeInfo& operator=(const TypeInfo&) = delete;
|
||||
TypeInfo& operator=(TypeInfo&&) = delete;
|
||||
|
||||
virtual std::unique_ptr<File> Deserialize(Env&, Deserializer&) const = 0;
|
||||
virtual std::unique_ptr<File> Deserialize(Deserializer&) const = 0;
|
||||
virtual std::unique_ptr<File> Create(Env&) const = 0;
|
||||
|
||||
virtual void UpdateTooltip() const noexcept = 0;
|
||||
@ -252,10 +254,6 @@ class Env {
|
||||
|
||||
class Watcher;
|
||||
|
||||
static void Push(Env&) noexcept;
|
||||
static Env& Peek() noexcept;
|
||||
static void Pop() noexcept;
|
||||
|
||||
Env() = delete;
|
||||
Env(const std::filesystem::path& npath) noexcept : npath_(npath) {
|
||||
}
|
||||
@ -278,6 +276,7 @@ class Env {
|
||||
void ExecHandle(const File::Event&) noexcept;
|
||||
|
||||
virtual void Save() noexcept = 0;
|
||||
virtual void Throw(std::exception_ptr&&) noexcept = 0;
|
||||
|
||||
const std::filesystem::path& npath() const noexcept { return npath_; }
|
||||
|
||||
@ -309,4 +308,172 @@ class Env::Watcher {
|
||||
Env* const env_;
|
||||
};
|
||||
|
||||
|
||||
class SerializerStream final {
|
||||
public:
|
||||
SerializerStream(const char* path, const char* mode);
|
||||
~SerializerStream() noexcept {
|
||||
std::fclose(fp_);
|
||||
}
|
||||
|
||||
// serializer requires write/flush
|
||||
size_t write(const void* ptr, size_t size) {
|
||||
const auto ret = static_cast<size_t>(std::fwrite(ptr, 1, size, fp_));
|
||||
off_ += ret;
|
||||
return ret;
|
||||
}
|
||||
void flush() {
|
||||
std::fflush(fp_);
|
||||
}
|
||||
|
||||
// deserializer requires read/available/empty/peekch/getch/ungetch
|
||||
size_t read(void* ptr, size_t size) {
|
||||
const auto ret = static_cast<size_t>(std::fread(ptr, 1, size, fp_));
|
||||
off_ += ret;
|
||||
return ret;
|
||||
}
|
||||
size_t available() const {
|
||||
return size_ - off_;
|
||||
}
|
||||
bool empty() const {
|
||||
return available() == 0;
|
||||
}
|
||||
char peekch() const {
|
||||
const auto c = std::getc(fp_);
|
||||
std::ungetc(c, fp_);
|
||||
return static_cast<char>(c);
|
||||
}
|
||||
char getch() {
|
||||
return static_cast<char>(std::getc(fp_));
|
||||
}
|
||||
void ungetch(char c) {
|
||||
std::ungetc(c, fp_);
|
||||
}
|
||||
|
||||
void Seek(size_t off) {
|
||||
if (0 != std::fseek(fp_, static_cast<long int>(off), SEEK_SET)) {
|
||||
throw nf7::Exception {"failed to seek"};
|
||||
}
|
||||
off_ = off;
|
||||
}
|
||||
|
||||
size_t offset() const noexcept { return off_; }
|
||||
|
||||
private:
|
||||
std::FILE* fp_;
|
||||
size_t off_;
|
||||
size_t size_;
|
||||
};
|
||||
class Serializer final :
|
||||
public yas::detail::binary_ostream<nf7::SerializerStream, yas::binary>,
|
||||
public yas::detail::oarchive_header<yas::binary> {
|
||||
public:
|
||||
using this_type = Serializer;
|
||||
|
||||
class ChunkGuard final {
|
||||
public:
|
||||
ChunkGuard(nf7::Serializer&);
|
||||
ChunkGuard(nf7::Serializer& ar, nf7::Env&) : ChunkGuard(ar) { }
|
||||
~ChunkGuard() noexcept; // use Env::Throw to handle errors
|
||||
private:
|
||||
Serializer* const ar_;
|
||||
size_t begin_;
|
||||
};
|
||||
|
||||
static void Save(const char* path, auto& v) {
|
||||
SerializerStream st {path, "wb"};
|
||||
Serializer ar {st};
|
||||
ar(v);
|
||||
}
|
||||
|
||||
Serializer(nf7::SerializerStream& st) :
|
||||
binary_ostream(st), oarchive_header(st), st_(&st) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Serializer& operator& (const T& v) {
|
||||
return yas::detail::serializer<
|
||||
yas::detail::type_properties<T>::value,
|
||||
yas::detail::serialization_method<T, this_type>::value, yas::binary, T>::
|
||||
save(*this, v);
|
||||
}
|
||||
Serializer& serialize() {
|
||||
return *this;
|
||||
}
|
||||
template<typename Head, typename... Tail>
|
||||
Serializer& serialize(const Head& head, const Tail&... tail) {
|
||||
return operator& (head).serialize(tail...);
|
||||
}
|
||||
template<typename... Args>
|
||||
Serializer& operator()(const Args&... args) {
|
||||
return serialize(args...);
|
||||
}
|
||||
|
||||
private:
|
||||
nf7::SerializerStream* const st_;
|
||||
};
|
||||
class Deserializer final :
|
||||
public yas::detail::binary_istream<nf7::SerializerStream, yas::binary>,
|
||||
public yas::detail::iarchive_header<yas::binary> {
|
||||
public:
|
||||
using this_type = Deserializer;
|
||||
|
||||
class ChunkGuard final {
|
||||
public:
|
||||
ChunkGuard(Deserializer& ar);
|
||||
ChunkGuard(Deserializer&, nf7::Env&);
|
||||
~ChunkGuard() noexcept; // use Env::Throw to handle errors
|
||||
void ValidateEnd();
|
||||
private:
|
||||
Deserializer* const ar_;
|
||||
size_t expect_;
|
||||
size_t begin_;
|
||||
nf7::Env* env_prev_ = nullptr;
|
||||
};
|
||||
|
||||
static void Load(nf7::Env& env, const char* path, auto& v) {
|
||||
try {
|
||||
SerializerStream st {path, "rb"};
|
||||
Deserializer ar {env, st};
|
||||
ar(v);
|
||||
} catch (nf7::Exception&) {
|
||||
throw;
|
||||
} catch (std::exception&) {
|
||||
throw nf7::Exception {"deserialization failure"};
|
||||
}
|
||||
}
|
||||
|
||||
Deserializer(nf7::Env& env, SerializerStream& st) :
|
||||
binary_istream(st), iarchive_header(st), env_(&env), st_(&st) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Deserializer& operator& (T&& v) {
|
||||
using RealType =
|
||||
typename std::remove_reference<typename std::remove_const<T>::type>::type;
|
||||
return yas::detail::serializer<
|
||||
yas::detail::type_properties<RealType>::value,
|
||||
yas::detail::serialization_method<RealType, Deserializer>::value,
|
||||
yas::binary, RealType>
|
||||
::load(*this, v);
|
||||
}
|
||||
Deserializer& serialize() {
|
||||
return *this;
|
||||
}
|
||||
template<typename Head, typename... Tail>
|
||||
Deserializer& serialize(Head&& head, Tail&&... tail) {
|
||||
return operator& (std::forward<Head>(head)).serialize(std::forward<Tail>(tail)...);
|
||||
}
|
||||
template<typename... Args>
|
||||
Deserializer& operator()(Args&& ... args) {
|
||||
return serialize(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
Env& env() const noexcept { return *env_; }
|
||||
|
||||
private:
|
||||
nf7::Env* env_;
|
||||
nf7::SerializerStream* const st_;
|
||||
};
|
||||
|
||||
} // namespace nf7
|
||||
|
@ -1,3 +0,0 @@
|
||||
add_executable(nf7-init)
|
||||
target_link_libraries(nf7-init PRIVATE yas)
|
||||
target_sources(nf7-init PRIVATE init.cc)
|
69
tool/init.cc
69
tool/init.cc
@ -1,69 +0,0 @@
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <yas/serialize.hpp>
|
||||
#include <yas/types/std/map.hpp>
|
||||
#include <yas/types/std/string.hpp>
|
||||
#include <yas/types/std/unordered_set.hpp>
|
||||
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
|
||||
using Ar = yas::binary_oarchive<yas::mem_ostream>;
|
||||
using L = std::function<void(void)>;
|
||||
|
||||
namespace yas::detail {
|
||||
template <size_t F>
|
||||
struct serializer<
|
||||
type_prop::not_a_fundamental,
|
||||
ser_case::use_internal_serializer,
|
||||
F,
|
||||
L> {
|
||||
public:
|
||||
static Ar& save(Ar& ar, const L& f) {
|
||||
f();
|
||||
return ar;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
L Write(Ar& ar, const Args&... args) {
|
||||
return [&args..., &ar]() { ar(args...); };
|
||||
}
|
||||
int main(void) {
|
||||
yas::mem_ostream os;
|
||||
Ar ar(os);
|
||||
|
||||
# define WINDOW_(shown) shown
|
||||
|
||||
ar("System/Dir"s, std::map<std::string, L> {
|
||||
{ "_audio"s,
|
||||
Write(ar, "Audio/Context"s) },
|
||||
{ "_imgui"s,
|
||||
Write(ar, "System/ImGui"s, ""s) },
|
||||
{ "_logger"s,
|
||||
Write(ar, "System/Logger"s, WINDOW_(true), 1024, false, false) },
|
||||
{ "_luajit"s,
|
||||
Write(ar, "LuaJIT/Context"s) },
|
||||
{ "home"s,
|
||||
Write(ar, "System/Dir"s,
|
||||
std::map<std::string, L> {},
|
||||
std::unordered_set<std::string> {},
|
||||
WINDOW_(false)) },
|
||||
}, std::unordered_set<std::string> {}, WINDOW_(true));
|
||||
|
||||
const auto buf = os.get_shared_buffer();
|
||||
for (size_t i = 0; i < buf.size;) {
|
||||
for (size_t j = 0; j < 32 && i < buf.size; ++j, ++i) {
|
||||
std::cout << static_cast<int>(buf.data.get()[i]) << ',';
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user