diff options
author | Roman Smrž <roman.smrz@seznam.cz> | 2020-04-16 21:42:45 +0200 |
---|---|---|
committer | Roman Smrž <roman.smrz@seznam.cz> | 2020-04-16 21:42:45 +0200 |
commit | 6cf5244bc514042fe419fffe1cd26a7f5e3c778f (patch) | |
tree | 4a72abf80980c3d10656bd82606a69329867d057 | |
parent | a76a9ad65fa549d2c1650bb5a7d9a657186edc43 (diff) |
Remove optional from load result
Makes loading of data well-defined for arbitrary object contents.
Introduce zero reference and object to represent missing or mismatched
parts.
-rw-r--r-- | include/erebos/message.h | 6 | ||||
-rw-r--r-- | include/erebos/storage.h | 16 | ||||
-rw-r--r-- | src/channel.cpp | 102 | ||||
-rw-r--r-- | src/channel.h | 6 | ||||
-rw-r--r-- | src/identity.cpp | 45 | ||||
-rw-r--r-- | src/identity.h | 2 | ||||
-rw-r--r-- | src/message.cpp | 39 | ||||
-rw-r--r-- | src/message.h | 8 | ||||
-rw-r--r-- | src/network.cpp | 14 | ||||
-rw-r--r-- | src/pubkey.cpp | 57 | ||||
-rw-r--r-- | src/pubkey.h | 37 | ||||
-rw-r--r-- | src/storage.cpp | 34 |
12 files changed, 184 insertions, 182 deletions
diff --git a/include/erebos/message.h b/include/erebos/message.h index 0b5e257..c94e8c3 100644 --- a/include/erebos/message.h +++ b/include/erebos/message.h @@ -14,9 +14,9 @@ class Identity; class DirectMessage { public: - const Identity & from() const; - const struct ZonedTime & time() const; - const std::string & text() const; + const std::optional<Identity> & from() const; + const std::optional<struct ZonedTime> & time() const; + std::string text() const; private: friend class DirectMessageThread; diff --git a/include/erebos/storage.h b/include/erebos/storage.h index d5ae45a..d46c056 100644 --- a/include/erebos/storage.h +++ b/include/erebos/storage.h @@ -72,6 +72,7 @@ public: PartialStorage derivePartialStorage() const; std::optional<Ref> ref(const Digest &) const; + Ref zref() const; std::optional<Object> loadObject(const Digest &) const; Ref storeObject(const Object &) const; @@ -103,6 +104,7 @@ public: explicit Digest(std::array<uint8_t, size> value): value(value) {} explicit Digest(const std::string &); explicit operator std::string() const; + bool isZero() const; const std::array<uint8_t, size> & arr() const { return value; } @@ -151,6 +153,7 @@ public: Ref & operator=(Ref &&) = default; static std::optional<Ref> create(Storage, const Digest &); + static Ref zcreate(Storage); constexpr operator bool() const { return true; } const Object operator*() const; @@ -265,7 +268,8 @@ class ObjectT public: typedef std::variant< RecordT<S>, - Blob> Variants; + Blob, + std::monostate> Variants; ObjectT(const ObjectT<S> &) = default; ObjectT(Variants content): content(content) {} @@ -282,7 +286,7 @@ public: std::vector<uint8_t>::const_iterator); static std::vector<ObjectT<S>> decodeMany(const S &, const std::vector<uint8_t> &); std::vector<uint8_t> encode() const; - static std::optional<ObjectT<S>> load(const typename S::Ref &); + static ObjectT<S> load(const typename S::Ref &); std::optional<RecordT<S>> asRecord() const; std::optional<Blob> asBlob() const; @@ -317,7 +321,7 @@ public: Stored & operator=(const Stored &) = default; Stored & operator=(Stored &&) = default; - static std::optional<Stored<T>> load(const Ref &); + static Stored<T> load(const Ref &); Ref store(const Storage &) const; bool operator==(const Stored<T> & other) const @@ -354,11 +358,9 @@ Stored<T> Storage::store(const T & val) const } template<typename T> -std::optional<Stored<T>> Stored<T>::load(const Ref & ref) +Stored<T> Stored<T>::load(const Ref & ref) { - if (auto val = T::load(ref)) - return Stored(ref, std::make_shared<T>(val.value())); - return std::nullopt; + return Stored(ref, std::make_shared<T>(T::load(ref))); } template<typename T> diff --git a/src/channel.cpp b/src/channel.cpp index 50c5f97..b13a71e 100644 --- a/src/channel.cpp +++ b/src/channel.cpp @@ -22,28 +22,25 @@ Ref ChannelRequestData::store(const Storage & st) const return st.storeObject(Record(std::move(items))); } -optional<ChannelRequestData> ChannelRequestData::load(const Ref & ref) +ChannelRequestData ChannelRequestData::load(const Ref & ref) { - auto rec = ref->asRecord(); - if (!rec) - return nullopt; - - remove_const<decltype(peers)>::type peers; - for (const auto & i : rec->items("peer")) - if (auto p = i.as<Signed<IdentityData>>()) - peers.push_back(*p); - - auto enc = rec->item("enc").asText(); - if (!enc || enc != "aes-128-gcm") - return nullopt; - - auto key = rec->item("key").as<PublicKexKey>(); - if (!key) - return nullopt; + if (auto rec = ref->asRecord()) { + remove_const<decltype(peers)>::type peers; + for (const auto & i : rec->items("peer")) + if (auto p = i.as<Signed<IdentityData>>()) + peers.push_back(*p); + + if (rec->item("enc").asText() == "aes-128-gcm") + if (auto key = rec->item("key").as<PublicKexKey>()) + return ChannelRequestData { + .peers = std::move(peers), + .key = *key, + }; + } return ChannelRequestData { - .peers = std::move(peers), - .key = *key, + .peers = {}, + .key = Stored<PublicKexKey>::load(ref.storage().zref()), }; } @@ -58,27 +55,18 @@ Ref ChannelAcceptData::store(const Storage & st) const return st.storeObject(Record(std::move(items))); } -optional<ChannelAcceptData> ChannelAcceptData::load(const Ref & ref) +ChannelAcceptData ChannelAcceptData::load(const Ref & ref) { - auto rec = ref->asRecord(); - if (!rec) - return nullopt; - - auto request = rec->item("req").as<ChannelRequest>(); - if (!request) - return nullopt; - - auto enc = rec->item("enc").asText(); - if (!enc || enc != "aes-128-gcm") - return nullopt; - - auto key = rec->item("key").as<PublicKexKey>(); - if (!key) - return nullopt; + if (auto rec = ref->asRecord()) + if (rec->item("enc").asText() == "aes-128-gcm") + return ChannelAcceptData { + .request = *rec->item("req").as<ChannelRequest>(), + .key = *rec->item("key").as<PublicKexKey>(), + }; return ChannelAcceptData { - .request = *request, - .key = *key, + .request = Stored<ChannelRequest>::load(ref.storage().zref()), + .key = Stored<PublicKexKey>::load(ref.storage().zref()), }; } @@ -114,26 +102,20 @@ Ref Channel::store(const Storage & st) const return st.storeObject(Record(std::move(items))); } -optional<Channel> Channel::load(const Ref & ref) +Channel Channel::load(const Ref & ref) { - auto rec = ref->asRecord(); - if (!rec) - return nullopt; - - remove_const<decltype(peers)>::type peers; - for (const auto & i : rec->items("peer")) - if (auto p = i.as<Signed<IdentityData>>()) - peers.push_back(*p); - - auto enc = rec->item("enc").asText(); - if (!enc || enc != "aes-128-gcm") - return nullopt; - - auto key = rec->item("key").asBinary(); - if (!key) - return nullopt; - - return Channel(peers, std::move(*key)); + if (auto rec = ref->asRecord()) { + remove_const<decltype(peers)>::type peers; + for (const auto & i : rec->items("peer")) + if (auto p = i.as<Signed<IdentityData>>()) + peers.push_back(*p); + + if (rec->item("enc").asText() == "aes-128-gcm") + if (auto key = rec->item("key").asBinary()) + return Channel(peers, std::move(*key)); + } + + return Channel({}, {}); } Stored<ChannelRequest> Channel::generateRequest(const Storage & st, @@ -146,12 +128,12 @@ Stored<ChannelRequest> Channel::generateRequest(const Storage & st, return signKey->sign(st.store(ChannelRequestData { .peers = self.ref()->digest() < peer.ref()->digest() ? vector<Stored<Signed<IdentityData>>> { - *Stored<Signed<IdentityData>>::load(*self.ref()), - *Stored<Signed<IdentityData>>::load(*peer.ref()), + Stored<Signed<IdentityData>>::load(*self.ref()), + Stored<Signed<IdentityData>>::load(*peer.ref()), } : vector<Stored<Signed<IdentityData>>> { - *Stored<Signed<IdentityData>>::load(*peer.ref()), - *Stored<Signed<IdentityData>>::load(*self.ref()), + Stored<Signed<IdentityData>>::load(*peer.ref()), + Stored<Signed<IdentityData>>::load(*self.ref()), }, .key = SecretKexKey::generate(st).pub(), })); diff --git a/src/channel.h b/src/channel.h index 100003c..1c7df30 100644 --- a/src/channel.h +++ b/src/channel.h @@ -9,7 +9,7 @@ namespace erebos { struct ChannelRequestData { Ref store(const Storage & st) const; - static optional<ChannelRequestData> load(const Ref &); + static ChannelRequestData load(const Ref &); const vector<Stored<Signed<IdentityData>>> peers; const Stored<PublicKexKey> key; @@ -20,7 +20,7 @@ typedef Signed<ChannelRequestData> ChannelRequest; struct ChannelAcceptData { Ref store(const Storage & st) const; - static optional<ChannelAcceptData> load(const Ref &); + static ChannelAcceptData load(const Ref &); Stored<class Channel> channel() const; @@ -40,7 +40,7 @@ public: {} Ref store(const Storage & st) const; - static optional<Channel> load(const Ref &); + static Channel load(const Ref &); static Stored<ChannelRequest> generateRequest(const Storage &, const Identity & self, const Identity & peer); diff --git a/src/identity.cpp b/src/identity.cpp index 3cba97c..2396b9f 100644 --- a/src/identity.cpp +++ b/src/identity.cpp @@ -24,12 +24,8 @@ optional<Identity> Identity::load(const vector<Ref> & refs) vector<Stored<Signed<IdentityData>>> data; data.reserve(refs.size()); - for (const auto & ref : refs) { - auto d = Stored<Signed<IdentityData>>::load(ref); - if (!d) - return nullopt; - data.push_back(*d); - } + for (const auto & ref : refs) + data.push_back(Stored<Signed<IdentityData>>::load(ref)); if (auto ptr = Priv::validate(data)) return Identity(ptr); @@ -124,27 +120,30 @@ void Identity::Builder::owner(const Identity & val) p->owner.emplace(val); } -optional<IdentityData> IdentityData::load(const Ref & ref) +IdentityData IdentityData::load(const Ref & ref) { - auto rec = ref->asRecord(); - if (!rec) - return nullopt; - - vector<Stored<Signed<IdentityData>>> prev; - for (auto p : rec->items("SPREV")) - if (const auto & x = p.as<Signed<IdentityData>>()) - prev.push_back(x.value()); + if (auto rec = ref->asRecord()) { + vector<Stored<Signed<IdentityData>>> prev; + for (auto p : rec->items("SPREV")) + if (const auto & x = p.as<Signed<IdentityData>>()) + prev.push_back(x.value()); - auto keyIdentity = rec->item("key-id").as<PublicKey>(); - if (!keyIdentity) - return nullopt; + if (auto keyIdentity = rec->item("key-id").as<PublicKey>()) + return IdentityData { + .prev = std::move(prev), + .name = rec->item("name").asText(), + .owner = rec->item("owner").as<Signed<IdentityData>>(), + .keyIdentity = keyIdentity.value(), + .keyMessage = rec->item("key-msg").as<PublicKey>(), + }; + } return IdentityData { - .prev = std::move(prev), - .name = rec->item("name").asText(), - .owner = rec->item("owner").as<Signed<IdentityData>>(), - .keyIdentity = keyIdentity.value(), - .keyMessage = rec->item("key-msg").as<PublicKey>(), + .prev = {}, + .name = nullopt, + .owner = nullopt, + .keyIdentity = Stored<PublicKey>::load(ref.storage().zref()), + .keyMessage = nullopt, }; } diff --git a/src/identity.h b/src/identity.h index 92ac34f..1dfc193 100644 --- a/src/identity.h +++ b/src/identity.h @@ -13,7 +13,7 @@ namespace erebos { class IdentityData { public: - static optional<IdentityData> load(const Ref &); + static IdentityData load(const Ref &); Ref store(const Storage & st) const; const vector<Stored<Signed<IdentityData>>> prev; diff --git a/src/message.cpp b/src/message.cpp index b7d4bda..354703e 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -48,11 +48,11 @@ DirectMessage::DirectMessage(Priv * p): p(p) {} -optional<DirectMessageData> DirectMessageData::load(const Ref & ref) +DirectMessageData DirectMessageData::load(const Ref & ref) { auto rec = ref->asRecord(); if (!rec) - return nullopt; + return DirectMessageData(); vector<Stored<DirectMessageData>> prev; for (auto p : rec->items("PREV")) @@ -60,16 +60,10 @@ optional<DirectMessageData> DirectMessageData::load(const Ref & ref) prev.push_back(*x); auto fref = rec->item("from").asRef(); - if (!fref) - return nullopt; - - auto from = Identity::load(*fref); - if (!from) - return nullopt; return DirectMessageData { .prev = std::move(prev), - .from = *from, + .from = fref ? Identity::load(*fref) : nullopt, .time = *rec->item("time").asDate(), .text = rec->item("text").asText().value(), }; @@ -81,27 +75,32 @@ Ref DirectMessageData::store(const Storage & st) const for (const auto prev : prev) items.emplace_back("PREV", prev.ref()); - items.emplace_back("from", from.ref().value()); - items.emplace_back("time", time); - items.emplace_back("text", text); + if (from) + items.emplace_back("from", from->ref().value()); + if (time) + items.emplace_back("time", *time); + if (text) + items.emplace_back("text", *text); return st.storeObject(Record(std::move(items))); } -const Identity & DirectMessage::from() const +const optional<Identity> & DirectMessage::from() const { return p->data->from; } -const ZonedTime & DirectMessage::time() const +const optional<ZonedTime> & DirectMessage::time() const { return p->data->time; } -const string & DirectMessage::text() const +string DirectMessage::text() const { - return p->data->text; + if (p->data->text) + return p->data->text.value(); + return ""; } @@ -138,7 +137,7 @@ DirectMessageThread::Iterator & DirectMessageThread::Iterator::operator++() auto ncur = p->next[0]; for (const auto & m : p->next) - if (m->time.time >= ncur->time.time) + if (!ncur->time || (m->time && m->time->time >= ncur->time->time)) ncur = m; p->current.emplace(DirectMessage(new DirectMessage::Priv { @@ -216,10 +215,6 @@ UUID DirectMessageService::uuid() const void DirectMessageService::handle(Context & ctx) const { - auto dm = Stored<DirectMessageData>::load(ctx.ref()); - if (!dm) - return; - auto pid = ctx.peer().identity(); if (!pid) return; @@ -228,7 +223,7 @@ void DirectMessageService::handle(Context & ctx) const unique_lock lock(threadLock); vector<Stored<DirectMessageData>> head(DirectMessageThread::Priv::getThreadLocked(powner).p->head); - head.push_back(*dm); + head.push_back(Stored<DirectMessageData>::load(ctx.ref())); filterAncestors(head); auto dmt = DirectMessageThread::Priv::updateThreadLocked(powner, std::move(head)); diff --git a/src/message.h b/src/message.h index 7e0f597..c4a3549 100644 --- a/src/message.h +++ b/src/message.h @@ -19,13 +19,13 @@ namespace erebos { struct DirectMessageData { - static optional<DirectMessageData> load(const Ref &); + static DirectMessageData load(const Ref &); Ref store(const Storage &) const; vector<Stored<DirectMessageData>> prev; - Identity from; - ZonedTime time; - string text; + optional<Identity> from; + optional<ZonedTime> time; + optional<string> text; }; struct DirectMessage::Priv diff --git a/src/network.cpp b/src/network.cpp index b31d949..91f1923 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -298,7 +298,7 @@ Server::Peer & Server::Priv::getPeer(const sockaddr_in & paddr) void Server::Priv::handlePacket(Server::Peer & peer, const TransportHeader & header, ReplyBuilder & reply) { unordered_set<Digest> plaintextRefs; - for (const auto & obj : collectStoredObjects(*Stored<Object>::load(*self.ref()))) + for (const auto & obj : collectStoredObjects(Stored<Object>::load(*self.ref()))) plaintextRefs.insert(obj.ref().digest()); optional<UUID> serviceType; @@ -397,9 +397,11 @@ void Server::Priv::handlePacket(Server::Peer & peer, const TransportHeader & hea auto cres = peer.tempStorage.copy(pref); if (auto r = std::get_if<Ref>(&cres)) { - if (auto acc = ChannelAccept::load(*r)) { + auto acc = ChannelAccept::load(*r); + if (holds_alternative<Identity>(peer.identity) && + acc.isSignedBy(std::get<Identity>(peer.identity).keyMessage())) { reply.header({ TransportHeader::Type::Acknowledged, pref }); - peer.channel.emplace<Stored<Channel>>(acc->data->channel()); + peer.channel.emplace<Stored<Channel>>(acc.data->channel()); } } } @@ -485,8 +487,10 @@ void Server::Peer::updateChannel(ReplyBuilder & reply) if (holds_alternative<shared_ptr<WaitingRef>>(channel)) { if (auto ref = std::get<shared_ptr<WaitingRef>>(channel)->check(reply)) { - if (auto req = Stored<ChannelRequest>::load(*ref)) { - if (auto acc = Channel::acceptRequest(server.self, std::get<Identity>(identity), *req)) { + auto req = Stored<ChannelRequest>::load(*ref); + if (holds_alternative<Identity>(identity) && + req->isSignedBy(std::get<Identity>(identity).keyMessage())) { + if (auto acc = Channel::acceptRequest(server.self, std::get<Identity>(identity), req)) { channel.emplace<Stored<ChannelAccept>>(*acc); reply.header({ TransportHeader::Type::ChannelAccept, acc->ref() }); reply.body(acc->ref()); diff --git a/src/pubkey.cpp b/src/pubkey.cpp index 0e83136..6d85d33 100644 --- a/src/pubkey.cpp +++ b/src/pubkey.cpp @@ -8,11 +8,11 @@ using std::string; using namespace erebos; -optional<PublicKey> PublicKey::load(const Ref & ref) +PublicKey PublicKey::load(const Ref & ref) { auto rec = ref->asRecord(); if (!rec) - return nullopt; + return PublicKey(nullptr); if (auto ktype = rec->item("type").asText()) if (ktype.value() != "ed25519") @@ -22,7 +22,7 @@ optional<PublicKey> PublicKey::load(const Ref & ref) return PublicKey(EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, nullptr, pubkey.value().data(), pubkey.value().size())); - return nullopt; + return PublicKey(nullptr); } Ref PublicKey::store(const Storage & st) const @@ -31,12 +31,14 @@ Ref PublicKey::store(const Storage & st) const items.emplace_back("type", "ed25519"); - vector<uint8_t> keyData; - size_t keyLen; - EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen); - keyData.resize(keyLen); - EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen); - items.emplace_back("pubkey", keyData); + if (key) { + vector<uint8_t> keyData; + size_t keyLen; + EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen); + keyData.resize(keyLen); + EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen); + items.emplace_back("pubkey", keyData); + } return st.storeObject(Record(std::move(items))); } @@ -110,19 +112,14 @@ vector<uint8_t> SecretKey::sign(const Digest & dgst) const return sigData; } -optional<Signature> Signature::load(const Ref & ref) +Signature Signature::load(const Ref & ref) { - auto rec = ref->asRecord(); - if (!rec) - return nullopt; + if (auto rec = ref->asRecord()) + if (auto key = rec->item("key").as<PublicKey>()) + if (auto sig = rec->item("sig").asBinary()) + return Signature(*key, *sig); - auto key = rec->item("key").as<PublicKey>(); - auto sig = rec->item("sig").asBinary(); - - if (!key || !sig) - return nullopt; - - return Signature(*key, *sig); + return Signature(Stored<PublicKey>::load(ref.storage().zref()), {}); } Ref Signature::store(const Storage & st) const @@ -151,11 +148,11 @@ bool Signature::verify(const Ref & ref) const } -optional<PublicKexKey> PublicKexKey::load(const Ref & ref) +PublicKexKey PublicKexKey::load(const Ref & ref) { auto rec = ref->asRecord(); if (!rec) - return nullopt; + return PublicKexKey(nullptr); if (auto ktype = rec->item("type").asText()) if (ktype.value() != "x25519") @@ -165,7 +162,7 @@ optional<PublicKexKey> PublicKexKey::load(const Ref & ref) return PublicKexKey(EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, nullptr, pubkey.value().data(), pubkey.value().size())); - return nullopt; + return PublicKexKey(nullptr); } Ref PublicKexKey::store(const Storage & st) const @@ -174,12 +171,14 @@ Ref PublicKexKey::store(const Storage & st) const items.emplace_back("type", "x25519"); - vector<uint8_t> keyData; - size_t keyLen; - EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen); - keyData.resize(keyLen); - EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen); - items.emplace_back("pubkey", keyData); + if (key) { + vector<uint8_t> keyData; + size_t keyLen; + EVP_PKEY_get_raw_public_key(key.get(), nullptr, &keyLen); + keyData.resize(keyLen); + EVP_PKEY_get_raw_public_key(key.get(), keyData.data(), &keyLen); + items.emplace_back("pubkey", keyData); + } return st.storeObject(Record(std::move(items))); } diff --git a/src/pubkey.h b/src/pubkey.h index c922dc7..7b80752 100644 --- a/src/pubkey.h +++ b/src/pubkey.h @@ -18,7 +18,7 @@ class PublicKey key(key, EVP_PKEY_free) {} friend class SecretKey; public: - static optional<PublicKey> load(const Ref &); + static PublicKey load(const Ref &); Ref store(const Storage &) const; const shared_ptr<EVP_PKEY> key; @@ -49,7 +49,7 @@ private: class Signature { public: - static optional<Signature> load(const Ref &); + static Signature load(const Ref &); Ref store(const Storage &) const; bool verify(const Ref &) const; @@ -67,7 +67,7 @@ template<typename T> class Signed { public: - static optional<Signed<T>> load(const Ref &); + static Signed<T> load(const Ref &); Ref store(const Storage &) const; bool isSignedBy(const Stored<PublicKey> &) const; @@ -90,23 +90,20 @@ Stored<Signed<T>> SecretKey::sign(const Stored<T> & val) const } template<typename T> -optional<Signed<T>> Signed<T>::load(const Ref & ref) +Signed<T> Signed<T>::load(const Ref & ref) { - auto rec = ref->asRecord(); - if (!rec) - return nullopt; - - auto data = rec->item("SDATA").as<T>(); - if (!data) - return nullopt; - - vector<Stored<Signature>> sigs; - for (auto item : rec->items("sig")) - if (auto sig = item.as<Signature>()) - if (sig.value()->verify(data.value().ref())) - sigs.push_back(sig.value()); - - return Signed(*data, sigs); + if (auto rec = ref->asRecord()) + if (auto data = rec->item("SDATA").as<T>()) { + vector<Stored<Signature>> sigs; + for (auto item : rec->items("sig")) + if (auto sig = item.as<Signature>()) + if (sig.value()->verify(data.value().ref())) + sigs.push_back(sig.value()); + + return Signed(*data, sigs); + } + + return Signed(Stored<T>::load(ref.storage().zref()), {}); } template<typename T> @@ -137,7 +134,7 @@ class PublicKexKey key(key, EVP_PKEY_free) {} friend class SecretKexKey; public: - static optional<PublicKexKey> load(const Ref &); + static PublicKexKey load(const Ref &); Ref store(const Storage &) const; const shared_ptr<EVP_PKEY> key; diff --git a/src/storage.cpp b/src/storage.cpp index 81a70e1..6a0669c 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -315,6 +315,11 @@ optional<Ref> Storage::ref(const Digest & digest) const return Ref::create(*this, digest); } +Ref Storage::zref() const +{ + return Ref::zcreate(*this); +} + Digest PartialStorage::Priv::storeBytes(const vector<uint8_t> & content) const { array<uint8_t, Digest::size> arr; @@ -346,6 +351,8 @@ optional<vector<uint8_t>> PartialStorage::Priv::loadBytes(const Digest & digest) optional<PartialObject> PartialStorage::loadObject(const Digest & digest) const { + if (digest.isZero()) + return PartialObject(monostate()); if (auto content = p->loadBytes(digest)) return PartialObject::decode(*this, *content); return nullopt; @@ -362,6 +369,8 @@ PartialRef PartialStorage::storeObject(const Blob & val) const optional<Object> Storage::loadObject(const Digest & digest) const { + if (digest.isZero()) + return Object(monostate()); if (auto content = p->loadBytes(digest)) return Object::decode(*this, *content); return nullopt; @@ -466,6 +475,13 @@ Digest::operator string() const return res; } +bool Digest::isZero() const +{ + for (uint8_t x : value) + if (x) return false; + return true; +} + PartialRef PartialRef::create(PartialStorage st, const Digest & digest) { @@ -517,6 +533,16 @@ optional<Ref> Ref::create(Storage st, const Digest & digest) return Ref(shared_ptr<Priv>(p)); } +Ref Ref::zcreate(Storage st) +{ + auto p = new Priv { + .storage = make_unique<PartialStorage>(st), + .digest = Digest(array<uint8_t, Digest::size> {}), + }; + + return Ref(shared_ptr<Priv>(p)); +} + const Object Ref::operator*() const { if (auto res = static_cast<Storage*>(p->storage.get())->loadObject(p->digest)) @@ -854,11 +880,9 @@ vector<uint8_t> ObjectT<S>::encode() const } template<class S> -optional<ObjectT<S>> ObjectT<S>::load(const typename S::Ref & ref) +ObjectT<S> ObjectT<S>::load(const typename S::Ref & ref) { - if (ref) - return *ref; - return nullopt; + return *ref; } template<class S> @@ -899,7 +923,7 @@ vector<Stored<Object>> erebos::collectStoredObjects(const Stored<Object> & from) if (auto rec = cur->asRecord()) for (const auto & item : rec->items()) if (auto ref = item.asRef()) - queue.push_back(*Stored<Object>::load(*ref)); + queue.push_back(Stored<Object>::load(*ref)); } return res; |