use crate::{make_map, make_map_with_root, BytesKey, Map};
use cid::Cid;
use ipld_amt::Amt;
use ipld_blockstore::BlockStore;
use ipld_hamt::Error;
use serde::{de::DeserializeOwned, Serialize};
use std::error::Error as StdError;
pub struct Multimap<'a, BS>(Map<'a, BS, Cid>);
impl<'a, BS> Multimap<'a, BS>
where
BS: BlockStore,
{
pub fn new(bs: &'a BS) -> Self {
Self(make_map(bs))
}
pub fn from_root(bs: &'a BS, cid: &Cid) -> Result<Self, Error> {
Ok(Self(make_map_with_root(cid, bs)?))
}
#[inline]
pub fn root(&mut self) -> Result<Cid, Error> {
self.0.flush()
}
pub fn add<V>(&mut self, key: BytesKey, value: V) -> Result<(), Box<dyn StdError>>
where
V: Serialize + DeserializeOwned,
{
let mut arr = self
.get::<V>(&key)?
.unwrap_or_else(|| Amt::new(self.0.store()));
arr.set(arr.count(), value)?;
let new_root = arr.flush()?;
Ok(self.0.set(key, new_root)?)
}
#[inline]
pub fn get<V>(&self, key: &[u8]) -> Result<Option<Amt<'a, V, BS>>, Box<dyn StdError>>
where
V: DeserializeOwned + Serialize,
{
match self.0.get(key)? {
Some(cid) => Ok(Some(Amt::load(&cid, self.0.store())?)),
None => Ok(None),
}
}
#[inline]
pub fn remove_all(&mut self, key: &[u8]) -> Result<(), Box<dyn StdError>> {
self.0
.delete(key)?
.ok_or("failed to delete from multimap")?;
Ok(())
}
pub fn for_each<F, V>(&self, key: &[u8], f: F) -> Result<(), Box<dyn StdError>>
where
V: Serialize + DeserializeOwned,
F: FnMut(u64, &V) -> Result<(), Box<dyn StdError>>,
{
if let Some(amt) = self.get::<V>(key)? {
amt.for_each(f)?;
}
Ok(())
}
pub fn for_all<F, V>(&self, mut f: F) -> Result<(), Box<dyn StdError>>
where
V: Serialize + DeserializeOwned,
F: FnMut(&BytesKey, &Amt<V, BS>) -> Result<(), Box<dyn StdError>>,
{
self.0.for_each::<_>(|key, arr_root| {
let arr = Amt::load(&arr_root, self.0.store())?;
f(key, &arr)
})?;
Ok(())
}
}