improve resilience to breaking changes of serialization format

This commit is contained in:
falsycat 2022-08-26 01:55:05 +09:00
parent 8c25d22955
commit 231f67d5dd
26 changed files with 488 additions and 237 deletions

View File

@ -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})

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}
};

View File

@ -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());
}

View File

@ -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 {

View File

@ -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 {
}

View File

@ -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 {

View File

@ -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_);
}

View File

@ -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 {

View File

@ -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;
}
};

View File

@ -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_);
}

View File

@ -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_);
}

View File

@ -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_);
}

View File

@ -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;
}
};

View File

@ -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:

View File

@ -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));

View File

@ -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());
}

View File

@ -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()});
}

View File

@ -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
View 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
View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -1,3 +0,0 @@
add_executable(nf7-init)
target_link_libraries(nf7-init PRIVATE yas)
target_sources(nf7-init PRIVATE init.cc)

View File

@ -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;
}