txmap 3.1.2

A concurrent transactional hash map for Rust with fine-grained locking, internal mutability and composable transactions
Documentation
use crate::{hasher::DefaultBuildHasher, indexer::Indexer, new_types::ShardCount};
use std::hash::{BuildHasher, Hash};

/// Schema trait for a prepared transaction.
///
/// Associates keys, parameters, and state types with a transaction.
/// Implemented by the [`tx_schema`] macro.
pub trait TxSchema<K>
where
    K: Hash + Eq,
{
    /// The raw (un-indexed) keys type.
    type Keys: TxKeys<K, Self::IndexedKeys>;
    /// The indexed keys type after hashing.
    type IndexedKeys;
    /// The parameters passed on each execution.
    type Params;
    /// The mutable working state (must be `Default`).
    type State: Default;
}

/// Raw keys that can be hashed into indexed keys.
pub trait TxKeys<K, IndexedKeys, S = DefaultBuildHasher>
where
    K: Hash + Eq,
    S: BuildHasher,
{
    /// Converts raw keys to indexed keys by computing hashes and shard indices.
    fn into_indexed(self, shard_count: ShardCount, indexer: &Indexer<S>) -> IndexedKeys;
}

/// Selects a single key from a set of indexed keys.
///
/// Implemented by key handle types generated by [`tx_schema`].
pub trait TxKeySelector<K, KEYS>
where
    K: Hash + Eq,
{
    /// Returns a reference to the selected key.
    fn get<'keys>(&self, keys: &'keys KEYS) -> &'keys K;
}

#[macro_export]
macro_rules! tx_schema {
    (
        $name:ident,
        keys: [ $($key:ident),* $(,)? ],
        params: { $($param_field:ident: $param_type:ty),* $(,)? },
        state: { $($state_field:ident: $state_type:ty),* $(,)? }
        $(,)?
    ) => {
        $crate::_paste! {
            pub use [<__private $name>] :: $name;
            pub use [<__private $name>] :: [<$name Keys>];
            pub use [<__private $name>] :: [<$name Params>];
            pub use [<__private $name>] :: [<$name State>];
            #[allow(non_snake_case)]
            mod [<__private $name>] {
                // schema
                pub struct $name <K>
                where
                    K: std::hash::Hash + Eq,
                {
                    _phantom: std::marker::PhantomData<K>,
                }
                impl<K> $crate::prelude::TxSchema<K> for $name<K>
                where
                    K: std::hash::Hash + Eq,
                {
                    type Keys =   [<$name Keys>]<K>;
                    type IndexedKeys = [<$name IndexedKeys>]<K>;
                    type Params = [<$name Params>];
                    type State =  [<$name State>];
                }
                impl<K> $name <K>
                where
                    K: std::hash::Hash + Eq,
                {
                    pub const SCHEMA: $name <K> = $name {
                        _phantom: std::marker::PhantomData,
                    };
                    $(
                        #[allow(non_upper_case_globals)]
                        pub const $key: [<$name _ $key>]<K> = [<$name _ $key>] {
                            _phantom: std::marker::PhantomData,
                        };
                    )*
                }

                // keys
                pub struct [<$name Keys>]<K>
                where
                    K: std::hash::Hash + Eq,
                {
                    $(pub $key: K,)*
                }

                // params
                pub struct [<$name Params>] {
                    $(pub $param_field: $param_type,)*
                }

                // state
                #[derive(Debug, Default, Hash, PartialEq, Eq)]
                pub struct [<$name State>] {
                    $(pub $state_field: $state_type,)*
                }

                pub struct [<$name IndexedKeys>]<K>
                where
                    K: std::hash::Hash + Eq,
                {
                    $(pub $key: $crate::prelude::TxKey<K>,)*
                }
                $(
                    #[allow(non_camel_case_types)]
                    pub struct [<$name _ $key>]<K>
                    where
                        K: std::hash::Hash + Eq,
                    {
                    _phantom: std::marker::PhantomData<K>,
                    }
                )*
                $(
                    impl<K> $crate::prelude::TxKeySelector<$crate::prelude::TxKey<K>, [<$name IndexedKeys>]<K>> for [<$name _ $key>]<K>
                    where
                        K: std::hash::Hash + Eq,
                    {
                        fn get<'keys>(&self, keys: &'keys [<$name IndexedKeys>]<K>) -> &'keys $crate::prelude::TxKey<K> {
                            &keys.$key
                        }
                    }
                )*
                impl<K, S> $crate::prelude::TxKeys<K, [<$name IndexedKeys>]<K>, S> for [<$name Keys>]<K>
                where
                    K: std::hash::Hash + Eq,
                    S: std::hash::BuildHasher,
                {
                    fn into_indexed(self, shard_count: $crate::prelude::ShardCount, indexer: &$crate::indexer::Indexer<S>) -> [<$name IndexedKeys>]<K> {
                        [<$name IndexedKeys>] {
                            $(
                                $key: indexer.indexed_key(shard_count, self.$key),
                            )*
                        }
                    }
                }
            }
        }
    };
}

pub use tx_schema;