txmap 0.1.0

A concurrent transactional hash map with fine-grained locking and internal mutability
Documentation
use crate::{
    builders::stem_builder::TxStemBuilder, custodian::Custodian, indexer::Indexer,
    result::MISSING_MUTEX_GUARD_ERROR, shard_count::ShardCount,
};
use std::hash::{DefaultHasher, Hash};

pub struct TxMap<K, V>
where
    K: Hash + Eq,
{
    indexer: Indexer,
    custodian: Custodian<K, V>,
}

impl<K, V> TxMap<K, V>
where
    K: Hash + Eq,
{
    pub fn new(shard_count: ShardCount) -> Self {
        let indexer = Indexer {
            shard_count: u8::from(shard_count),
            hasher_creator: || Box::new(DefaultHasher::new()),
        };
        Self {
            indexer,
            custodian: Custodian::new(shard_count),
        }
    }
    pub fn clear(&self) {
        let all_guards = self.custodian.all_guards();
        for mut mutex_guard in all_guards {
            mutex_guard.1.clear();
        }
    }
    pub fn len(&self) -> usize {
        let mut total_length = 0;
        let all_guards = self.custodian.all_guards();
        for mutex_guard in all_guards {
            total_length += mutex_guard.1.len();
        }
        total_length
    }
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
    pub fn insert(&self, key: K, value: V) -> Option<V> {
        let shard_index = self.indexer.index(&key);
        let mut mutex_guards = self.custodian.guards(1 << shard_index);
        let mutex_guard = mutex_guards
            .get_mut(shard_index)
            .expect(MISSING_MUTEX_GUARD_ERROR);
        mutex_guard.insert(key, value)
    }
    pub fn remove(&self, key: &K) -> Option<V> {
        let shard_index = self.indexer.index(key);
        let mut mutex_guards = self.custodian.guards(1 << shard_index);
        let mutex_guard = mutex_guards
            .get_mut(shard_index)
            .expect(MISSING_MUTEX_GUARD_ERROR);
        mutex_guard.remove(key)
    }
    pub fn get_with<T, R>(&self, key: &K, transform: T) -> Option<R>
    where
        T: FnOnce(&V) -> R,
    {
        let shard_index = self.indexer.index(key);
        let mut mutex_guards = self.custodian.guards(1 << shard_index);
        let mutex_guard = mutex_guards
            .get_mut(shard_index)
            .expect(MISSING_MUTEX_GUARD_ERROR);
        mutex_guard.get(key).map(transform)
    }
    pub fn fold<T, R, C, A>(&self, initial: R, convert: C, accumulate: A) -> R
    where
        C: Fn(&K, &V) -> Option<T>,
        A: Fn(R, T) -> R,
    {
        self.custodian
            .all_guards()
            .iter()
            .flat_map(|guard| guard.1.iter())
            .filter_map(|(key, value)| convert(key, value))
            .fold(initial, accumulate)
    }
    pub fn transaction<'txmap>(&'txmap self) -> TxStemBuilder<'txmap, K, V> {
        TxStemBuilder {
            indexer: self.indexer,
            custodian: &self.custodian,
        }
    }
}

impl<K, V> TxMap<K, V>
where
    K: Hash + Eq,
    V: Copy,
{
    pub fn get_copied(&self, key: &K) -> Option<V> {
        self.get_with(key, |v| *v)
    }
}

impl<K, V> TxMap<K, V>
where
    K: Hash + Eq,
    V: Clone,
{
    pub fn get_cloned(&self, key: &K) -> Option<V> {
        self.get_with(key, |v| v.clone())
    }
}