txmap 2.1.1

A concurrent transactional hash map for Rust with fine-grained locking, internal mutability and composable transactions
Documentation
use crate::{
    custodian::Custodian,
    immediate::{
        guard::Guard,
        ops::{
            get_op::GetOp, insert_default_if_absent_op::InsertDefaultIfAbsentOp,
            insert_default_op::InsertDefaultOp, insert_with_if_absent_op::InsertWithIfAbsentOp,
            insert_with_op::InsertWithOp, modify_op::ModifyOp, move_value_op::MoveValueOp,
            op_trait::OpTrait, remove_op::RemoveOp, remove_where_op::RemoveWhereOp,
            swap_value_op::SwapValueOp, update_op::UpdateOp,
        },
        transaction::ImmediateTransaction,
    },
    indexer::Indexer,
    lock_policies::lock_policy::LockPolicy,
    result::TxResult,
};
use std::{hash::Hash, marker::PhantomData};

pub struct ImmediateBuilderPhase;
pub struct ImmediateBuildablePhase;

pub struct ImmediateTxBuilder<'tx, K, V, L, STATE, PHASE = ImmediateBuilderPhase>
where
    K: Hash + Eq + 'tx,
    V: 'tx,
    L: LockPolicy + 'tx,
    STATE: Default + 'tx,
{
    pub(crate) custodian: &'tx Custodian<K, V, L>,
    pub(crate) guards: Vec<Guard<'tx, K, V, STATE>>,
    #[allow(clippy::type_complexity)]
    pub(crate) ops: Vec<Box<dyn OpTrait<K, V, L, STATE> + 'tx>>,
    pub(crate) _phase: PhantomData<PHASE>,
}

impl<'tx, K, V, L, STATE> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuilderPhase>
where
    K: Hash + Eq + 'tx,
    V: 'tx,
    L: LockPolicy + 'tx,
    STATE: Default + 'tx,
{
    pub fn require(
        mut self,
        name: impl AsRef<str>,
        key: K,
        condition: impl Fn(&K, Option<&V>, &mut STATE) -> bool + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuilderPhase> {
        let guard = Guard {
            name: name.as_ref().into(),
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            condition: Box::new(condition),
            _phantom: PhantomData,
        };
        self.guards.push(guard);
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
}

impl<'tx, K, V, L, STATE, PHASE> ImmediateTxBuilder<'tx, K, V, L, STATE, PHASE>
where
    K: Hash + Eq + 'tx,
    V: 'tx,
    L: LockPolicy + 'tx,
    STATE: Default + 'tx,
{
    pub fn get(
        mut self,
        key: K,
        get: impl Fn(&K, Option<&V>, &mut STATE) + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase> {
        let op = GetOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            get: Box::new(get),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn insert_default(
        mut self,
        key: K,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
        V: Default,
    {
        let op = InsertDefaultOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn insert_default_if_absent(
        mut self,
        key: K,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
        V: Default,
    {
        let op = InsertDefaultIfAbsentOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn insert_with(
        mut self,
        key: K,
        value_generator: impl Fn(&K, &mut STATE) -> V + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
    {
        let op = InsertWithOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            value_generator: Box::new(value_generator),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn insert_with_if_absent(
        mut self,
        key: K,
        value_generator: impl Fn(&K, &mut STATE) -> V + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
    {
        let op = InsertWithIfAbsentOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            value_generator: Box::new(value_generator),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn modify(
        mut self,
        key: K,
        mutate: impl Fn(&K, &mut V, &mut STATE) + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase> {
        let op = ModifyOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            mutate: Box::new(mutate),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn move_value(
        mut self,
        key_from: K,
        key_to: K,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
    {
        let op = MoveValueOp {
            key_from: Indexer::indexed_key(self.custodian.shard_count, key_from),
            key_to: Indexer::indexed_key(self.custodian.shard_count, key_to),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn remove(
        mut self,
        key: K,
        on_remove: impl Fn(Option<(K, V)>, &mut STATE) + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase> {
        let op = RemoveOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            on_remove: Box::new(on_remove),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn remove_where(
        mut self,
        key: K,
        condition: impl Fn(&K, &V, &mut STATE) -> bool + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase> {
        let op = RemoveWhereOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            condition: Box::new(condition),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn swap_value(
        mut self,
        key_a: K,
        key_b: K,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
    {
        let op = SwapValueOp {
            key_a: Indexer::indexed_key(self.custodian.shard_count, key_a),
            key_b: Indexer::indexed_key(self.custodian.shard_count, key_b),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
    pub fn update(
        mut self,
        key: K,
        transform: impl Fn(&K, Option<&V>, &mut STATE) -> Option<V> + 'tx,
    ) -> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
    where
        K: Clone,
    {
        let op = UpdateOp {
            key: Indexer::indexed_key(self.custodian.shard_count, key),
            transform: Box::new(transform),
        };
        self.ops.push(Box::new(op));
        ImmediateTxBuilder {
            custodian: self.custodian,
            guards: self.guards,
            ops: self.ops,
            _phase: PhantomData,
        }
    }
}

impl<'tx, K, V, L, STATE> ImmediateTxBuilder<'tx, K, V, L, STATE, ImmediateBuildablePhase>
where
    K: Hash + Eq + 'tx,
    V: 'tx,
    L: LockPolicy + 'tx,
    STATE: Default + 'tx,
{
    #[must_use]
    pub fn execute(self) -> TxResult<STATE> {
        let Self {
            custodian,
            guards,
            ops,
            _phase,
        } = self;
        ImmediateTransaction {
            custodian,
            guards,
            ops,
        }
        .execute()
    }
}