use super::hash::{Hash, HashedKey, Hasher};
use super::immutable::Hamt;
use super::node::{
insert_rec, remove_eq_rec, remove_rec, replace_rec, replace_with_rec, update_rec,
};
use std::iter::FromIterator;
use std::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InsertError {
EntryExists,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RemoveError {
KeyNotFound,
ValueNotMatching,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpdateError<T> {
KeyNotFound,
ValueCallbackError(T),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReplaceError {
KeyNotFound,
}
pub struct HamtMut<K, V, H> {
root: Hamt<K, V, H>,
}
impl<H, K, V> Clone for HamtMut<K, V, H> {
fn clone(&self) -> Self {
Self {
root: self.root.clone(),
}
}
}
impl<'a, H, K, V> From<&'a Hamt<K, V, H>> for HamtMut<K, V, H> {
fn from(t: &'a Hamt<K, V, H>) -> Self {
HamtMut { root: t.clone() }
}
}
impl<H: Hasher + Default, K: Clone + Eq + Hash, V: Clone> HamtMut<K, V, H> {
pub fn new() -> Self {
HamtMut { root: Hamt::new() }
}
}
impl<H, K, V> HamtMut<K, V, H> {
pub fn freeze(self) -> Hamt<K, V, H> {
self.root
}
}
impl<H: Hasher + Default, K: Clone + Eq + Hash, V: Clone> HamtMut<K, V, H> {
pub fn insert(&mut self, k: K, v: V) -> Result<(), InsertError> {
let h = HashedKey::compute(self.root.hasher, &k);
let newroot = insert_rec(&self.root.root, h, 0, k, v)?;
self.root = Hamt {
root: newroot,
hasher: PhantomData,
};
Ok(())
}
}
impl<H: Hasher + Default, K: Eq + Hash + Clone, V: PartialEq + Clone> HamtMut<K, V, H> {
pub fn remove_match(&mut self, k: &K, v: &V) -> Result<(), RemoveError> {
let h = HashedKey::compute(self.root.hasher, &k);
let newroot = remove_eq_rec(&self.root.root, h, 0, k, v)?;
match newroot {
None => self.root = Hamt::new(),
Some(r) => {
self.root = Hamt {
root: r,
hasher: PhantomData,
}
}
};
Ok(())
}
}
impl<H: Hasher + Default, K: Clone + Eq + Hash, V: Clone> HamtMut<K, V, H> {
pub fn remove(&mut self, k: &K) -> Result<(), RemoveError> {
let h = HashedKey::compute(self.root.hasher, &k);
let newroot = remove_rec(&self.root.root, h, 0, k)?;
match newroot {
None => self.root = Hamt::new(),
Some(r) => {
self.root = Hamt {
root: r,
hasher: PhantomData,
}
}
}
Ok(())
}
}
impl<H: Hasher + Default, K: Eq + Hash + Clone, V: Clone> HamtMut<K, V, H> {
pub fn replace(&mut self, k: &K, v: V) -> Result<V, ReplaceError> {
let h = HashedKey::compute(self.root.hasher, &k);
let (newroot, oldv) = replace_rec(&self.root.root, h, 0, k, v)?;
self.root = Hamt {
root: newroot,
hasher: PhantomData,
};
Ok(oldv)
}
pub fn replace_with<F>(&mut self, k: &K, f: F) -> Result<(), ReplaceError>
where
F: FnOnce(&V) -> V,
{
let h = HashedKey::compute(self.root.hasher, &k);
let newroot = replace_with_rec(&self.root.root, h, 0, k, f)?;
self.root = Hamt {
root: newroot,
hasher: PhantomData,
};
Ok(())
}
}
impl<H: Hasher + Default, K: Eq + Hash + Clone, V: Clone> HamtMut<K, V, H> {
pub fn update<F, U>(&mut self, k: &K, f: F) -> Result<(), UpdateError<U>>
where
F: FnOnce(&V) -> Result<Option<V>, U>,
{
let h = HashedKey::compute(self.root.hasher, &k);
let newroot = update_rec(&self.root.root, h, 0, k, f)?;
match newroot {
None => self.root = Hamt::new(),
Some(r) => {
self.root = Hamt {
root: r,
hasher: PhantomData,
}
}
};
Ok(())
}
pub fn insert_or_update<F, E>(&mut self, k: K, v: V, f: F) -> Result<(), E>
where
F: FnOnce(&V) -> Result<Option<V>, E>,
V: Clone,
{
match self.update(&k, f) {
Ok(new_self) => Ok(new_self),
Err(UpdateError::KeyNotFound) =>
{
Ok(self.insert(k, v).unwrap())
}
Err(UpdateError::ValueCallbackError(x)) => Err(x),
}
}
pub fn insert_or_update_simple<F>(&mut self, k: K, v: V, f: F) -> ()
where
F: for<'a> FnOnce(&'a V) -> Option<V>,
V: Clone,
{
match self.update(&k, |x| Ok(f(x))) {
Ok(new_self) => new_self,
Err(UpdateError::ValueCallbackError(())) => unreachable!(),
Err(UpdateError::KeyNotFound) => {
self.insert(k, v).unwrap()
}
}
}
}
impl<H: Default + Hasher, K: Eq + Hash + Clone, V: Clone> FromIterator<(K, V)>
for HamtMut<K, V, H>
{
fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
let mut h = HamtMut::new();
for (k, v) in iter {
match h.insert(k, v) {
Err(_) => {}
Ok(()) => (),
}
}
h
}
}