#pragma once #include #include #include #include #include #include #include namespace erebos { class Storage; class Digest; class Ref; class Object; template class Stored; class Storage { public: Storage(const Storage &) = default; Storage & operator=(const Storage &) = delete; static std::optional open(std::filesystem::path path); bool operator==(const Storage &) const; bool operator!=(const Storage &) const; std::optional ref(const Digest &) const; std::optional loadObject(const Digest &) const; Ref storeObject(const Object &) const; Ref storeObject(const class Record &) const; Ref storeObject(const class Blob &) const; template Stored store(const T &) const; void storeKey(Ref pubref, const std::vector &) const; std::optional> loadKey(Ref pubref) const; private: friend class Ref; struct Priv; const std::shared_ptr p; Storage(const std::shared_ptr p): p(p) {} }; class Digest { public: static constexpr size_t size = 32; Digest(const Digest &) = default; Digest & operator=(const Digest &) = delete; explicit Digest(std::array value): value(value) {} explicit Digest(const std::string &); explicit operator std::string() const; const std::array & arr() const { return value; } bool operator==(const Digest & other) const { return value == other.value; } bool operator!=(const Digest & other) const { return value != other.value; } bool operator<(const Digest & other) const { return value < other.value; } bool operator<=(const Digest & other) const { return value <= other.value; } bool operator>(const Digest & other) const { return value > other.value; } bool operator>=(const Digest & other) const { return value >= other.value; } private: std::array value; }; class Ref { public: Ref(const Ref &) = default; Ref & operator=(const Ref &) = delete; static std::optional create(Storage, const Digest &); const Digest & digest() const; const Object & operator*() const; const Object * operator->() const; const Storage & storage() const; private: friend class Storage; struct Priv; const std::shared_ptr p; Ref(const std::shared_ptr p): p(p) {} }; class Record { public: class Item { public: typedef std::variant< std::monostate, int, std::string, std::vector, Ref> Variant; Item(const std::string & name): Item(name, std::monostate()) {} Item(const std::string & name, Variant value): name(name), value(value) {} template Item(const std::string & name, const Stored & value): Item(name, value.ref) {} Item(const Item &) = default; Item & operator=(const Item &) = delete; operator bool() const; std::optional asInteger() const; std::optional asText() const; std::optional> asBinary() const; std::optional asRef() const; template std::optional> as() const; private: friend class Record; std::string name; Variant value; }; private: Record(const std::shared_ptr> & ptr): ptr(ptr) {} public: Record(const std::vector &); Record(std::vector &&); std::vector encode() const; const std::vector & items() const; Item item(const std::string & name) const; Item operator[](const std::string & name) const; std::vector items(const std::string & name) const; private: friend class Object; std::vector encodeInner() const; static Record decode(Storage, std::vector::const_iterator, std::vector::const_iterator); const std::shared_ptr> ptr; }; class Blob { public: Blob(const std::vector &); const std::vector & data() const { return *ptr; } std::vector encode() const; private: friend class Object; std::vector encodeInner() const; static Blob decode(Storage, std::vector::const_iterator, std::vector::const_iterator); Blob(std::shared_ptr> ptr): ptr(ptr) {} const std::shared_ptr> ptr; }; class Object { public: typedef std::variant< Record, Blob> Variants; Object(const Object &) = default; Object(Variants content): content(content) {} Object & operator=(const Object &) = delete; static std::optional decode(Storage, const std::vector &); std::vector encode() const; static std::optional load(const Ref &); std::optional asRecord() const; std::optional asBlob() const; private: friend class Record; friend class Blob; Variants content; }; template std::optional> Record::Item::as() const { if (auto ref = asRef()) return Stored::load(ref.value()); return std::nullopt; } template class Stored { Stored(Ref ref, std::shared_ptr val): ref(ref), val(val) {} friend class Storage; public: static std::optional> load(const Ref &); Ref store(const Storage &) const; bool operator==(const Stored & other) const { return ref.digest() == other.ref.digest(); } bool operator!=(const Stored & other) const { return ref.digest() != other.ref.digest(); } bool operator<(const Stored & other) const { return ref.digest() < other.ref.digest(); } bool operator<=(const Stored & other) const { return ref.digest() <= other.ref.digest(); } bool operator>(const Stored & other) const { return ref.digest() > other.ref.digest(); } bool operator>=(const Stored & other) const { return ref.digest() >= other.ref.digest(); } const T & operator*() const { return *val; } const T * operator->() const { return val.get(); } std::vector> previous() const; bool precedes(const Stored &) const; const Ref ref; const std::shared_ptr val; }; template Stored Storage::store(const T & val) const { return Stored(val.store(*this), std::make_shared(val)); } template std::optional> Stored::load(const Ref & ref) { if (auto val = T::load(ref)) return Stored(ref, std::make_shared(val.value())); return std::nullopt; } template Ref Stored::store(const Storage & st) const { if (st == ref.storage()) return ref; return st.storeObject(*ref); } template std::vector> Stored::previous() const { auto rec = ref->asRecord(); if (!rec) return {}; auto sdata = rec->item("SDATA").asRef(); if (sdata) { auto drec = sdata.value()->asRecord(); if (!drec) return {}; std::vector> res; for (const auto & i : drec->items("SPREV")) if (auto x = i.as()) res.push_back(*x); return res; } std::vector> res; for (auto & i : rec->items("PREV")) if (auto x = i.as()) res.push_back(*x); return res; } template bool Stored::precedes(const Stored & other) const { for (const auto & x : other.previous()) { if (*this == x || precedes(x)) return true; } return false; } }