#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace nf7 { class Exception; class File; class Context; class Env; using Serializer = yas::binary_oarchive; using Deserializer = yas::binary_iarchive; class Exception : public std::nested_exception { public: Exception() = delete; Exception(std::string_view msg, std::source_location loc = std::source_location::current()) noexcept : nested_exception(), msg_(msg), srcloc_(loc) { } virtual ~Exception() = default; Exception(const Exception&) = default; Exception(Exception&&) = default; Exception& operator=(const Exception&) = delete; Exception& operator=(Exception&&) = delete; virtual void UpdatePanic() const noexcept; const std::string& msg() const noexcept { return msg_; } const std::source_location& srcloc() const noexcept { return srcloc_; } std::exception_ptr reason() const noexcept { return nested_ptr(); } private: const std::string msg_; const std::source_location srcloc_; }; class DeserializeException : public Exception { public: using Exception::Exception; }; class ExpiredException : public Exception { public: using Exception::Exception; }; class File { public: struct Event; class TypeInfo; class Interface; class Path; class NotFoundException; class NotImplementedException; using Id = uint64_t; static const std::map& registry() noexcept; static const TypeInfo& registry(std::string_view); File() = delete; File(const TypeInfo&, Env&) noexcept; virtual ~File() noexcept; File(const File&) = delete; File(File&&) = delete; File& operator=(const File&) = delete; File& operator=(File&&) = delete; virtual void Serialize(Serializer&) const noexcept = 0; virtual std::unique_ptr Clone(Env&) const noexcept = 0; void MoveUnder(File& parent, std::string_view) noexcept; void MakeAsRoot() noexcept; void Isolate() noexcept; virtual void Update() noexcept { } virtual void Handle(const Event&) noexcept { } virtual File* Find(std::string_view) const noexcept { return nullptr; } File& FindOrThrow(std::string_view name) const; File& ResolveOrThrow(const Path&) const; File& ResolveOrThrow(std::string_view) const; File& ResolveUpwardOrThrow(const Path&) const; File& ResolveUpwardOrThrow(std::string_view) const; virtual Interface* interface(const std::type_info&) noexcept = 0; Interface& interfaceOrThrow(const std::type_info&); template T* interface() noexcept { return dynamic_cast(interface(typeid(T))); } template T& interfaceOrThrow() { return dynamic_cast(interfaceOrThrow(typeid(T))); } Path abspath() const noexcept; File& ancestorOrThrow(size_t) const; const TypeInfo& type() const noexcept { return *type_; } Env& env() const noexcept { return *env_; } Id id() const noexcept { return id_; } File* parent() const noexcept { return parent_; } const std::string& name() const noexcept { return name_; } protected: void Touch() noexcept; private: const TypeInfo* const type_; Env* const env_; Id id_ = 0; File* parent_ = nullptr; std::string name_; }; struct File::Event final { public: enum Type { // emitted by system (do not emit manually) kAdd, kRemove, // can be emitted from inside of File kUpdate, // can be emitted from outside of File kReqFocus, }; Id id; Type type; }; class File::TypeInfo { public: TypeInfo() = delete; TypeInfo(const std::string& name, std::unordered_set&&) noexcept; ~TypeInfo() noexcept; TypeInfo(const TypeInfo&) = delete; TypeInfo(TypeInfo&&) = delete; TypeInfo& operator=(const TypeInfo&) = delete; TypeInfo& operator=(TypeInfo&&) = delete; virtual std::unique_ptr Deserialize(Env&, Deserializer&) const = 0; virtual std::unique_ptr Create(Env&) const = 0; virtual void UpdateTooltip() const noexcept = 0; const std::string& name() const noexcept { return name_; } const std::unordered_set& flags() const noexcept { return flags_; } private: const std::string name_; const std::unordered_set flags_; }; class File::Interface { public: Interface() = default; virtual ~Interface() = default; Interface(const Interface&) = default; Interface(Interface&&) = default; Interface& operator=(const Interface&) = default; Interface& operator=(Interface&&) = default; }; class File::Path { public: Path() = default; Path(std::initializer_list terms) noexcept : terms_(terms.begin(), terms.end()) { } Path(std::vector&& terms) noexcept : terms_(std::move(terms)) { } Path(const Path&) = default; Path(Path&&) = default; Path& operator=(const Path&) = default; Path& operator=(Path&&) = default; bool operator==(const Path& p) const noexcept { return terms_ == p.terms_; } bool operator!=(const Path& p) const noexcept { return terms_ != p.terms_; } Path(Deserializer&); void Serialize(Serializer&) const noexcept; static Path Parse(std::string_view); std::string Stringify() const noexcept; static void ValidateTerm(std::string_view); void Validate() const; std::span terms() const noexcept { return terms_; } const std::string& terms(size_t i) const noexcept { return terms_[i]; } private: std::vector terms_; }; class File::NotFoundException : public Exception { public: using Exception::Exception; }; class File::NotImplementedException : public Exception { public: using Exception::Exception; }; class Context { public: Context() = delete; Context(File&, const std::shared_ptr& = nullptr) noexcept; Context(Env&, File::Id, const std::shared_ptr& = nullptr) noexcept; virtual ~Context() noexcept; virtual void CleanUp() noexcept { } virtual void Abort() noexcept { } virtual size_t GetMemoryUsage() const noexcept { return 0; } virtual std::string GetDescription() const noexcept { return ""; } Env& env() const noexcept { return *env_; } File::Id initiator() const noexcept { return initiator_; } std::shared_ptr parent() const noexcept { return parent_.lock(); } size_t depth() const noexcept { return depth_; } private: Env* const env_; const File::Id initiator_; const std::weak_ptr parent_; const size_t depth_; }; class Env { public: friend class ProxyEnv; 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) { } virtual ~Env() = default; Env(const Env&) = delete; Env(Env&&) = delete; Env& operator=(const Env&) = delete; Env& operator=(Env&&) = delete; virtual File* GetFile(File::Id) const noexcept = 0; File& GetFileOrThrow(File::Id) const; // all Exec*() methods are thread-safe using Task = std::function; virtual void ExecMain(const std::shared_ptr&, Task&&) noexcept = 0; virtual void ExecSub(const std::shared_ptr&, Task&&) noexcept = 0; virtual void ExecAsync(const std::shared_ptr&, Task&&) noexcept = 0; virtual void Handle(const File::Event&) noexcept = 0; virtual void Save() noexcept = 0; const std::filesystem::path& npath() const noexcept { return npath_; } protected: friend class nf7::File; virtual File::Id AddFile(File&) noexcept = 0; virtual void RemoveFile(File::Id) noexcept = 0; virtual void AddWatcher(File::Id, Watcher&) noexcept = 0; virtual void RemoveWatcher(Watcher&) noexcept = 0; private: std::filesystem::path npath_; }; class Env::Watcher { public: Watcher(Env&) noexcept; virtual ~Watcher() noexcept; Watcher(const Watcher&) = delete; Watcher(Watcher&&) = delete; Watcher& operator=(const Watcher&) = delete; Watcher& operator=(Watcher&&) = delete; virtual void Handle(const File::Event&) noexcept = 0; void Watch(File::Id) noexcept; private: Env* const env_; }; } // namespace nf7