noosphere_core/data/
versioned_map.rs1use anyhow::Result;
2use cid::Cid;
3use libipld_cbor::DagCborCodec;
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5use std::{fmt::Display, hash::Hash, marker::PhantomData};
6
7use noosphere_collections::hamt::{Hamt, Hash as HamtHash, Sha256};
8use noosphere_storage::BlockStore;
9
10use noosphere_common::ConditionalSync;
11
12use super::{ChangelogIpld, DelegationIpld, IdentityIpld, Jwt, Link, MemoIpld, RevocationIpld};
13
14pub type ContentIpld = VersionedMapIpld<String, Link<MemoIpld>>;
16pub type IdentitiesIpld = VersionedMapIpld<String, IdentityIpld>;
18pub type DelegationsIpld = VersionedMapIpld<Link<Jwt>, DelegationIpld>;
20pub type RevocationsIpld = VersionedMapIpld<Link<Jwt>, RevocationIpld>;
22
23pub trait VersionedMapKey:
25 Serialize + DeserializeOwned + HamtHash + Clone + Eq + Ord + ConditionalSync + Display
26{
27}
28
29impl<T> VersionedMapKey for T where
30 T: Serialize + DeserializeOwned + HamtHash + Clone + Eq + Ord + ConditionalSync + Display
31{
32}
33
34pub trait VersionedMapValue:
36 Serialize + DeserializeOwned + Clone + Eq + Hash + ConditionalSync
37{
38}
39
40impl<T> VersionedMapValue for T where
41 T: Serialize + DeserializeOwned + Clone + Eq + Hash + ConditionalSync
42{
43}
44
45#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
48pub enum MapOperation<Key, Value> {
49 Add {
51 key: Key,
53 value: Value,
55 },
56 Remove {
58 key: Key,
60 },
61}
62
63#[derive(Debug, Default, Eq, PartialEq, Clone, Serialize, Deserialize)]
67pub struct VersionedMapIpld<Key, Value>
68where
69 Key: VersionedMapKey,
70 Value: VersionedMapValue,
71{
72 pub hamt: Cid,
74 pub changelog: Cid,
81
82 #[allow(missing_docs)]
83 #[serde(skip)]
84 pub signature: PhantomData<(Key, Value)>,
85}
86
87impl<Key, Value> VersionedMapIpld<Key, Value>
88where
89 Key: VersionedMapKey,
90 Value: VersionedMapValue,
91{
92 pub async fn load_hamt<S: BlockStore>(&self, store: &S) -> Result<Hamt<S, Value, Key, Sha256>> {
94 Hamt::load(&self.hamt, store.clone()).await
95 }
96
97 pub async fn load_changelog<S: BlockStore>(
99 &self,
100 store: &S,
101 ) -> Result<ChangelogIpld<MapOperation<Key, Value>>> {
102 store.load::<DagCborCodec, _>(&self.changelog).await
103 }
104
105 pub async fn empty<S: BlockStore>(store: &mut S) -> Result<Self> {
111 let mut hamt = Hamt::<S, Value, Key, Sha256>::new(store.clone());
112 let changelog = ChangelogIpld::<MapOperation<Key, Value>>::default();
113
114 let changelog_cid = store.save::<DagCborCodec, _>(&changelog).await?;
115 let hamt_cid = hamt.flush().await?;
116
117 Ok(VersionedMapIpld {
118 hamt: hamt_cid,
119 changelog: changelog_cid,
120 signature: Default::default(),
121 })
122 }
123}