chiralmap 0.1.3

Left-Right map using IndexMap
Documentation
//! Implementing left-right for indexmap: [`SingleMap`]

use indexmap::IndexMap;
use left_right::Absorb;
use std::hash::Hash;

use crate::{ChiralMapConfig, chiral_map::Operation};

#[cfg(feature = "metrics")]
use crate::metrics::Metrics;

/// A hash map that supports the left-right algorythm for fast reads.
/// This will duplicate the map and its data so it will take double memory.
/// The advantage is that reads are non blocking while writes need to decide
/// when to flush the data.
/// This also makes this map eventually consistent.
#[derive(Clone)]
pub(crate) struct SingleMap<K, V> {
    map: IndexMap<K, V>,

    #[cfg(feature = "metrics")]
    metrics: Metrics,
}

impl<K, V> Absorb<Operation<K, V>> for SingleMap<K, V>
where
    K: Hash + Eq + Clone,
    V: Clone,
{
    fn absorb_first(&mut self, operation: &mut Operation<K, V>, _other: &Self) {
        self.step(operation.clone());
    }

    fn absorb_second(&mut self, operation: Operation<K, V>, _other: &Self) {
        self.step(operation);
    }

    fn sync_with(&mut self, first: &Self) {
        first.map.iter().for_each(|(k, v)| {
            self.map.insert(k.clone(), v.clone());
        });
    }
}

impl<K, V> SingleMap<K, V>
where
    K: Hash + Eq + Clone,
    V: Clone,
{
    pub(crate) fn step(&mut self, operation: Operation<K, V>) {
        match operation {
            Operation::Insert(k, v) => {
                self.map.insert(k, v);

                #[cfg(feature = "metrics")]
                self.metrics.inserted(&self.map);
            }
            Operation::Delete(k) => {
                self.map.swap_remove(&k);

                #[cfg(feature = "metrics")]
                self.metrics.removed(&self.map);
            }
        }
    }
}

impl<K, V> SingleMap<K, V>
where
    K: Hash + Eq + Clone,
    V: Clone,
{
    pub(crate) fn new(config: &ChiralMapConfig) -> Self {
        let map = IndexMap::<K, V>::with_capacity(config.initial_capacity);

        Self {
            map,
            #[cfg(feature = "metrics")]
            metrics: Metrics::new(config),
        }
    }

    pub(crate) fn get(&self, k: &K) -> Option<&V> {
        self.map.get(k)
    }
}