use anyhow::Result;
use cid::Cid;
use libipld_cbor::DagCborCodec;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use std::{fmt::Display, hash::Hash, marker::PhantomData};
use noosphere_collections::hamt::{Hamt, Hash as HamtHash, Sha256};
use noosphere_storage::BlockStore;
use super::{ChangelogIpld, DelegationIpld, IdentityIpld, Jwt, Link, MemoIpld, RevocationIpld};
pub type IdentitiesIpld = VersionedMapIpld<String, IdentityIpld>;
pub type ContentIpld = VersionedMapIpld<String, Link<MemoIpld>>;
pub type DelegationsIpld = VersionedMapIpld<Link<Jwt>, DelegationIpld>;
pub type RevocationsIpld = VersionedMapIpld<Link<Jwt>, RevocationIpld>;
#[cfg(not(target_arch = "wasm32"))]
pub trait VersionedMapSendSync: Send + Sync {}
#[cfg(not(target_arch = "wasm32"))]
impl<T> VersionedMapSendSync for T where T: Send + Sync {}
#[cfg(target_arch = "wasm32")]
pub trait VersionedMapSendSync {}
#[cfg(target_arch = "wasm32")]
impl<T> VersionedMapSendSync for T {}
pub trait VersionedMapKey:
Serialize + DeserializeOwned + HamtHash + Clone + Eq + Ord + VersionedMapSendSync + Display
{
}
impl<T> VersionedMapKey for T where
T: Serialize + DeserializeOwned + HamtHash + Clone + Eq + Ord + VersionedMapSendSync + Display
{
}
pub trait VersionedMapValue:
Serialize + DeserializeOwned + Clone + Eq + Hash + VersionedMapSendSync
{
}
impl<T> VersionedMapValue for T where
T: Serialize + DeserializeOwned + Clone + Eq + Hash + VersionedMapSendSync
{
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub enum MapOperation<Key, Value> {
Add { key: Key, value: Value },
Remove { key: Key },
}
#[derive(Debug, Default, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct VersionedMapIpld<Key, Value>
where
Key: VersionedMapKey,
Value: VersionedMapValue,
{
pub hamt: Cid,
pub changelog: Cid,
#[serde(skip)]
pub signature: PhantomData<(Key, Value)>,
}
impl<Key, Value> VersionedMapIpld<Key, Value>
where
Key: VersionedMapKey,
Value: VersionedMapValue,
{
pub async fn load_hamt<S: BlockStore>(&self, store: &S) -> Result<Hamt<S, Value, Key, Sha256>> {
Hamt::load(&self.hamt, store.clone()).await
}
pub async fn load_changelog<S: BlockStore>(
&self,
store: &S,
) -> Result<ChangelogIpld<MapOperation<Key, Value>>> {
store.load::<DagCborCodec, _>(&self.changelog).await
}
pub async fn empty<S: BlockStore>(store: &mut S) -> Result<Self> {
let mut hamt = Hamt::<S, Value, Key, Sha256>::new(store.clone());
let changelog = ChangelogIpld::<MapOperation<Key, Value>>::default();
let changelog_cid = store.save::<DagCborCodec, _>(&changelog).await?;
let hamt_cid = hamt.flush().await?;
Ok(VersionedMapIpld {
hamt: hamt_cid,
changelog: changelog_cid,
signature: Default::default(),
})
}
}