surelock 0.1.0

Deadlock-free locks for Rust with compile time guarantees, incremental locks, and atomic lock sets.
Documentation
//! [`Acquirable`] implementations for tuples of mutex references.
//!
//! Generated via macro for arities 2 through 12.
//!
//! All tuple elements implement [`MutexRef`], so any combination of
//! bare references, `Arc`, `Rc`, and `Box` is accepted.
//!
//! The 2-tuple supports different levels per element (multi-level).
//! Arities 3--12 require the same level.

use crate::{
    acquirable::{Acquirable, MutexRef},
    level::{MaxLevel, MinLevel},
    mutex::guard::MutexGuard,
};

// -- 2-tuple: multi-level, different T per element --

impl<'a, A, B> Acquirable<'a> for (A, B)
where
    A: MutexRef<'a>,
    B: MutexRef<'a, RawMtx = A::RawMtx>,
    A::Lvl: MinLevel<B::Lvl> + MaxLevel<B::Lvl>,
{
    type MinLvl = <A::Lvl as MinLevel<B::Lvl>>::Min;
    type MaxLvl = <A::Lvl as MaxLevel<B::Lvl>>::Max;
    type Guard = (
        MutexGuard<'a, A::RawMtx, A::Data>,
        MutexGuard<'a, B::RawMtx, B::Data>,
    );

    fn collect_ids(&self, out: &mut alloc::vec::Vec<crate::id::LockId>) {
        out.push(self.0.id());
        out.push(self.1.id());
    }

    #[allow(clippy::expect_used, non_snake_case)]
    fn lock_sorted(&'a self, sorted_indices: &[usize]) -> Self::Guard {
        let mut GA: Option<MutexGuard<'a, A::RawMtx, A::Data>> = None;
        let mut GB: Option<MutexGuard<'a, B::RawMtx, B::Data>> = None;

        for &target in sorted_indices {
            match target {
                0 => GA = Some(self.0.lock_ref()),
                1 => GB = Some(self.1.lock_ref()),
                _ => unreachable!(),
            }
        }

        (
            GA.expect("lock_sorted: missing index 0"),
            GB.expect("lock_sorted: missing index 1"),
        )
    }
}

// -- 3-12 tuples: same level, same backend, different T per element --
//
// Each element implements MutexRef with associated types. The macro
// constrains all elements to share the same Lvl and RawMtx.

macro_rules! impl_lockable_tuple_same_level {
    ($n:literal: $first_idx:tt $first_T:ident $first_G:ident $(, $idx:tt $T:ident $G:ident)+) => {
        impl<'a, $first_G, $($G,)+> Acquirable<'a>
            for ($first_G, $($G,)+)
        where
            $first_G: MutexRef<'a>,
            $($G: MutexRef<'a, Lvl = $first_G::Lvl, RawMtx = $first_G::RawMtx>,)+
        {
            type MinLvl = $first_G::Lvl;
            type MaxLvl = $first_G::Lvl;
            type Guard = (
                MutexGuard<'a, $first_G::RawMtx, $first_G::Data>,
                $(MutexGuard<'a, $G::RawMtx, $G::Data>,)+
            );

            fn collect_ids(&self, out: &mut alloc::vec::Vec<crate::id::LockId>) {
                out.push(self.$first_idx.id());
                $(out.push(self.$idx.id());)+
            }

            #[allow(clippy::expect_used, non_snake_case)]
            fn lock_sorted(&'a self, sorted_indices: &[usize]) -> Self::Guard {
                let mut $first_T: Option<MutexGuard<'a, $first_G::RawMtx, $first_G::Data>> = None;
                $(let mut $T: Option<MutexGuard<'a, $G::RawMtx, $G::Data>> = None;)+

                for &target in sorted_indices {
                    match target {
                        $first_idx => $first_T = Some(self.$first_idx.lock_ref()),
                        $($idx => $T = Some(self.$idx.lock_ref()),)+
                        _ => unreachable!(),
                    }
                }

                (
                    $first_T.expect("lock_sorted: missing index in permutation"),
                    $($T.expect("lock_sorted: missing index in permutation"),)+
                )
            }
        }
    };
}

impl_lockable_tuple_same_level!( 3: 0 A GA, 1 B GB, 2 C GC);
impl_lockable_tuple_same_level!( 4: 0 A GA, 1 B GB, 2 C GC, 3 D GD);
impl_lockable_tuple_same_level!( 5: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE);
impl_lockable_tuple_same_level!( 6: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF);
impl_lockable_tuple_same_level!( 7: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF, 6 G GG);
impl_lockable_tuple_same_level!( 8: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF, 6 G GG, 7 H GH);
impl_lockable_tuple_same_level!( 9: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF, 6 G GG, 7 H GH, 8 I GI);
impl_lockable_tuple_same_level!(10: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF, 6 G GG, 7 H GH, 8 I GI, 9 J GJ);
impl_lockable_tuple_same_level!(11: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF, 6 G GG, 7 H GH, 8 I GI, 9 J GJ, 10 K GK);
impl_lockable_tuple_same_level!(12: 0 A GA, 1 B GB, 2 C GC, 3 D GD, 4 E GE, 5 F GF, 6 G GG, 7 H GH, 8 I GI, 9 J GJ, 10 K GK, 11 L GL);