use std::marker::PhantomData; use crate::{ context::{ContextGuard, LockingIterator, LockingTuple}, lockable::{Lockable, RawLock, Sharable}, ThreadKey, }; impl<'c, A, B, O> LockingTuple<'c, A, B, O> { fn transmute(self) -> LockingTuple<'c, C, B, O> { LockingTuple { _lockable: PhantomData, key: self.key, tuple: self.tuple, outer: self.outer, } } } // Some day I need to invent variadic generics for Rust to make this easier for // myself macro_rules! lock_impl { ($self: expr, $field: tt) => { unsafe { $self.tuple.$field.raw_write(); ( ContextGuard { _key: &$self.key, guard: $self.tuple.$field.guard(), }, $self.transmute(), ) } }; } macro_rules! try_lock_impl { ($self: expr, $field: tt) => { unsafe { if $self.tuple.$field.raw_try_write() { Ok(( ContextGuard { _key: $self.key, guard: $self.tuple.$field.guard(), }, $self.transmute(), )) } else { Err($self) } } }; } macro_rules! lock_mut_impl { ($self: expr, $field: tt) => { unsafe { $self.tuple.$field.raw_write(); ContextGuard { _key: $self.key, guard: $self.tuple.$field.guard(), } } }; } macro_rules! try_lock_mut_impl { ($self: expr, $field: tt) => { unsafe { if $self.tuple.$field.raw_try_write() { Some(ContextGuard { _key: $self.key, guard: $self.tuple.$field.guard(), }) } else { None } } }; } macro_rules! read_impl { ($self: expr, $field: tt) => { unsafe { $self.tuple.$field.raw_read(); ( ContextGuard { _key: &$self.key, guard: $self.tuple.$field.read_guard(), }, $self.transmute(), ) } }; } macro_rules! try_read_impl { ($self: expr, $field: tt) => { unsafe { if $self.tuple.$field.raw_try_read() { Ok(( ContextGuard { _key: $self.key, guard: $self.tuple.$field.read_guard(), }, $self.transmute(), )) } else { Err($self) } } }; } macro_rules! read_mut_impl { ($self: expr, $field: tt) => { unsafe { $self.tuple.$field.raw_read(); ContextGuard { _key: $self.key, guard: $self.tuple.$field.read_guard(), } } }; } macro_rules! try_read_mut_impl { ($self: expr, $field: tt) => { unsafe { if $self.tuple.$field.raw_try_read() { Some(ContextGuard { _key: $self.key, guard: $self.tuple.$field.read_guard(), }) } else { None } } }; } macro_rules! recurse_impl { ($self: expr, $field: tt) => { LockingTuple { _lockable: PhantomData, key: $self.key, tuple: &$self.tuple.$field, outer: $self.transmute(), } }; } macro_rules! recurse_iter_impl { ($self: expr, $field: tt) => { LockingIterator { key: $self.key, iterator: $self.tuple.$field.into_iter(), outer: $self.transmute(), } }; } // I created these types to help reduce the complexity of the method return // types. But now I've added so much functionality that these types are just as // complicates. Oh well. type LockReturn<'a, 'context, Guarded, L, C, O> = ( ContextGuard<'a, ::Guard<'a>, ThreadKey>, LockingTuple<'context, L, C, O>, ); type TryLockReturn<'a, 'context, Guarded, L, C, O, This> = Result, This>; type ReadReturn<'a, 'context, Guarded, L, C, O> = ( ContextGuard<'a, ::ReadGuard<'a>, ThreadKey>, LockingTuple<'context, L, C, O>, ); type TryReadReturn<'a, 'context, Guarded, L, C, O, This> = Result, This>; type RecurseReturn<'context, Inner, L, C, O> = LockingTuple<'context, Inner, Inner, LockingTuple<'context, L, C, O>>; type RecurseIterReturn<'context, Inner, L, C, O> = LockingIterator< 'context, <&'context Inner as IntoIterator>::IntoIter, LockingTuple<'context, L, C, O>, >; impl LockingTuple<'_, T, C, Outer> { /// Exit out of the current scope of the locking tuple into the parent. // Luckily, this only needs one implementation pub fn exit(self) -> Outer { self.outer } } impl<'context, A: RawLock + Lockable, Outer> LockingTuple<'context, (A,), (A,), Outer> { /// Lock the first element, and return a new tuple where the first element /// is inaccessible. #[must_use] pub fn lock_0<'a>(self) -> LockReturn<'a, 'context, A, ((),), (A,), Outer> where 'context: 'a, { lock_impl!(self, 0) } /// Attempts to lock the first element without blocking, and return a new tuple /// where the first element is inaccessible. /// /// # Errors /// /// If the element is already locked, `Err` is returned with the original /// tuple. pub fn try_lock_0<'a>(self) -> TryLockReturn<'a, 'context, A, ((),), (A,), Outer, Self> where 'context: 'a, { try_lock_impl!(self, 0) } /// Lock the first element. The tuple becomes unusable until the returned /// guard is dropped. #[must_use] pub fn lock_mut_0(&mut self) -> ContextGuard<'_, A::Guard<'_>, ThreadKey> { lock_mut_impl!(self, 0) } /// Attempts to lock the first element without blocking. If successful, the /// tuple becomes unusable until the returned guard is dropped. If the element /// is already locked, `None` is returned. #[must_use] pub fn try_lock_mut_0(&mut self) -> Option, ThreadKey>> { try_lock_mut_impl!(self, 0) } } impl<'context, A: RawLock + Sharable, Outer> LockingTuple<'context, (A,), (A,), Outer> { /// Acquire a shared lock to the first element, and return a new tuple where /// the first element is inaccessible. #[must_use] pub fn read_0<'a>(self) -> ReadReturn<'a, 'context, A, ((),), (A,), Outer> where 'context: 'a, { read_impl!(self, 0) } /// Attempts to acquire a shared lock the first element without blocking, and /// return a new tuple where the first element is inaccessible. /// /// # Errors /// /// If the element is already exclusively locked, `Err` is returned with the original /// tuple. pub fn try_read_0<'a>(self) -> TryReadReturn<'a, 'context, A, ((),), (A,), Outer, Self> where 'context: 'a, { try_read_impl!(self, 0) } /// Acquire a shared lock to the first element. The tuple becomes unusable /// until the returned guard is dropped. #[must_use] pub fn read_mut_0(&mut self) -> ContextGuard<'_, A::ReadGuard<'_>, ThreadKey> { read_mut_impl!(self, 0) } /// Attempts to acquire a shared lock the first element without blocking. If /// successful, the tuple becomes unusable until the returned guard is /// dropped. If the element is already exclusively locked, `None` is returned. #[must_use] pub fn try_read_mut_0(&mut self) -> Option, ThreadKey>> { try_read_mut_impl!(self, 0) } } impl<'context, A, O> LockingTuple<'context, (A,), (A,), O> { /// Consume the tuple, and return the first element as a new tuple. #[must_use] pub fn recurse_0(self) -> RecurseReturn<'context, A, ((),), (A,), O> { recurse_impl!(self, 0) } /// Consume the tuple, and return the first element as a locking iterator. pub fn recurse_0_iter(self) -> RecurseIterReturn<'context, A, ((),), (A,), O> where &'context A: IntoIterator, { recurse_iter_impl!(self, 0) } } impl<'context, A: RawLock + Lockable, B, B0, O> LockingTuple<'context, (A, B), (A, B0), O> { /// Lock the first element, and return a new tuple where the first element /// is inaccessible. #[must_use] pub fn lock_0<'a>(self) -> LockReturn<'a, 'context, A, ((), B), (A, B0), O> where 'context: 'a, { lock_impl!(self, 0) } /// Lock the first element. The tuple becomes unusable until the returned /// guard is dropped. #[must_use] pub fn lock_mut_0(&mut self) -> ContextGuard<'_, A::Guard<'_>, ThreadKey> { lock_mut_impl!(self, 0) } /// Attempts to lock the first element without blocking, and return a new tuple /// where the first element is inaccessible. /// /// # Errors /// /// If the element is already locked, `Err` is returned with the original /// tuple. pub fn try_lock_0<'a>(self) -> TryLockReturn<'a, 'context, A, ((), B), (A, B0), O, Self> where 'context: 'a, { try_lock_impl!(self, 0) } /// Attempts to lock the first element without blocking. If successful, the /// tuple becomes unusable until the returned guard is dropped. If the element /// is already locked, `None` is returned. #[must_use] pub fn try_lock_mut_0(&mut self) -> Option, ThreadKey>> { try_lock_mut_impl!(self, 0) } } impl<'context, A: RawLock + Sharable, B, B0, O> LockingTuple<'context, (A, B), (A, B0), O> { /// Acquire a shared lock to the first element, and return a new tuple where /// the first element is inaccessible. #[must_use] pub fn read_0<'a>(self) -> ReadReturn<'a, 'context, A, ((), B), (A, B0), O> where 'context: 'a, { read_impl!(self, 0) } /// Attempts to acquire a shared lock the first element without blocking, and /// return a new tuple where the first element is inaccessible. /// /// # Errors /// /// If the element is already exclusively locked, `Err` is returned with the original /// tuple. pub fn try_read_0<'a>(self) -> TryReadReturn<'a, 'context, A, ((), B), (A, B0), O, Self> where 'context: 'a, { try_read_impl!(self, 0) } /// Acquire a shared lock to the first element. The tuple becomes unusable /// until the returned guard is dropped. #[must_use] pub fn read_mut_0(&mut self) -> ContextGuard<'_, A::ReadGuard<'_>, ThreadKey> { read_mut_impl!(self, 0) } /// Attempts to acquire a shared lock the first element without blocking. If /// successful, the tuple becomes unusable until the returned guard is /// dropped. If the element is already exclusively locked, `None` is returned. #[must_use] pub fn try_read_mut_0(&mut self) -> Option, ThreadKey>> { try_read_mut_impl!(self, 0) } } impl<'context, A, B, B0, O> LockingTuple<'context, (A, B), (A, B0), O> { /// Consume the tuple, and return the first element as a new tuple. #[must_use] pub fn recurse_0(self) -> RecurseReturn<'context, A, ((), B), (A, B0), O> { recurse_impl!(self, 0) } /// Consume the tuple, and return the first element as a locking iterator. pub fn recurse_0_iter(self) -> RecurseIterReturn<'context, A, ((), B), (A, B0), O> where &'context A: IntoIterator, { recurse_iter_impl!(self, 0) } } impl<'context, A: Lockable + RawLock, B, O> LockingTuple<'context, (A, B), (A, B), O> { /// Lock the first element, and return the second element as a new tuple. #[must_use] pub fn lock_and_recurse<'a>( self, ) -> ( ContextGuard<'a, ::Guard<'a>, ThreadKey>, LockingTuple<'context, B, B, O>, ) where 'context: 'a, { unsafe { self.tuple.0.raw_write(); ( ContextGuard { _key: self.key, guard: self.tuple.0.guard(), }, LockingTuple { _lockable: PhantomData, key: self.key, tuple: &self.tuple.1, outer: self.outer, }, ) } } } impl<'context, A, A0, B: RawLock + Lockable, O> LockingTuple<'context, (A, B), (A0, B), O> { /// Lock the second element, and return a new tuple where the first and second /// elements are inaccessible. #[must_use] pub fn lock_1<'a>(self) -> LockReturn<'a, 'context, B, ((), ()), (A0, B), O> where 'context: 'a, { lock_impl!(self, 1) } /// Lock the second element. The tuple becomes unusable until the returned /// guard is dropped. #[must_use] pub fn lock_mut_1(&mut self) -> ContextGuard<'_, B::Guard<'_>, ThreadKey> { lock_mut_impl!(self, 1) } /// Attempts to lock the second element without blocking, and return a new tuple /// where the first element is inaccessible. /// /// # Errors /// /// If the element is already locked, `Err` is returned with the original /// tuple. pub fn try_lock_1<'a>(self) -> TryLockReturn<'a, 'context, B, ((), ()), (A0, B), O, Self> where 'context: 'a, { try_lock_impl!(self, 1) } /// Attempts to lock the second element without blocking. If successful, the /// tuple becomes unusable until the returned guard is dropped. If the element /// is already locked, `None` is returned. #[must_use] pub fn try_lock_mut_1(&mut self) -> Option, ThreadKey>> { try_lock_mut_impl!(self, 1) } } impl<'context, A, A0, B: RawLock + Sharable, O> LockingTuple<'context, (A, B), (A0, B), O> { /// Acquire a shared lock to the second element, and return a new tuple where /// the second element is inaccessible. #[must_use] pub fn read_1<'a>(self) -> ReadReturn<'a, 'context, B, ((), ()), (A0, B), O> where 'context: 'a, { read_impl!(self, 1) } /// Attempts to acquire a shared lock the second element without blocking, and /// return a new tuple where the second element is inaccessible. /// /// # Errors /// /// If the element is already exclusively locked, `Err` is returned with the original /// tuple. pub fn try_read_1<'a>(self) -> TryReadReturn<'a, 'context, B, ((), ()), (A0, B), O, Self> where 'context: 'a, { try_read_impl!(self, 1) } /// Acquire a shared lock to the second element. The tuple becomes unusable /// until the returned guard is dropped. #[must_use] pub fn read_mut_1(&mut self) -> ContextGuard<'_, B::ReadGuard<'_>, ThreadKey> { read_mut_impl!(self, 1) } /// Attempts to acquire a shared lock the second element without blocking. If /// successful, the tuple becomes unusable until the returned guard is /// dropped. If the element is already exclusively locked, `None` is returned. #[must_use] pub fn try_read_mut_1(&mut self) -> Option, ThreadKey>> { try_read_mut_impl!(self, 1) } } impl<'context, A, A0, B, O> LockingTuple<'context, (A, B), (A0, B), O> { /// Consume the tuple, and return the second element as a new tuple. #[must_use] pub fn recurse_1(self) -> RecurseReturn<'context, B, ((), ()), (A0, B), O> { recurse_impl!(self, 1) } /// Consume the tuple, and return the second element as a locking iterator. pub fn recurse_1_iter(self) -> RecurseIterReturn<'context, B, (A, ()), (A0, B), O> where &'context B: IntoIterator, { recurse_iter_impl!(self, 1) } } impl<'context, A: RawLock + Lockable, B, B0, C, C0, O> LockingTuple<'context, (A, B, C), (A, B0, C0), O> { /// Lock the first element, and return a new tuple where the first element /// is inaccessible. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn lock_0<'a>(self) -> LockReturn<'a, 'context, A, ((), B, C), (A, B0, C0), O> where 'context: 'a, { lock_impl!(self, 0) } /// Lock the first element. The tuple becomes unusable until the returned /// guard is dropped. #[must_use] pub fn lock_mut_0(&mut self) -> ContextGuard<'_, A::Guard<'_>, ThreadKey> { lock_mut_impl!(self, 0) } /// Attempts to lock the first element without blocking. If successful, the /// tuple becomes unusable until the returned guard is dropped. If the element /// is already locked, `None` is returned. #[must_use] pub fn try_lock_mut_0(&mut self) -> Option, ThreadKey>> { try_lock_mut_impl!(self, 0) } } impl<'context, A: RawLock + Sharable, B, B0, C, C0, O> LockingTuple<'context, (A, B, C), (A, B0, C0), O> { /// Acquire a shared lock to the first element, and return a new tuple where /// the first element is inaccessible. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn read_0<'a>(self) -> ReadReturn<'a, 'context, A, ((), B, C), (A, B0, C0), O> where 'context: 'a, { read_impl!(self, 0) } /// Acquire a shared lock to the first element. The tuple becomes unusable /// until the returned guard is dropped. #[must_use] pub fn read_mut_0(&mut self) -> ContextGuard<'_, A::ReadGuard<'_>, ThreadKey> { read_mut_impl!(self, 0) } /// Attempts to acquire a shared lock the first element without blocking. If /// successful, the tuple becomes unusable until the returned guard is /// dropped. If the element is already exclusively locked, `None` is returned. #[must_use] pub fn try_read_mut_0(&mut self) -> Option, ThreadKey>> { try_read_mut_impl!(self, 0) } } impl<'context, A, B, B0, C, C0, O> LockingTuple<'context, (A, B, C), (A, B0, C0), O> { /// Consume the tuple, and return the first element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_0(self) -> RecurseReturn<'context, A, ((), B, C), (A, B0, C0), O> { recurse_impl!(self, 0) } /// Consume the tuple, and return the first element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_0_iter(self) -> RecurseIterReturn<'context, A, ((), B, C), (A, B0, C0), O> where &'context A: IntoIterator, { recurse_iter_impl!(self, 0) } } impl<'context, A, A0, B: RawLock + Lockable, C, C0, O> LockingTuple<'context, (A, B, C), (A0, B, C0), O> { /// Lock the second element, and return a new tuple where the first and second /// elements are inaccessible. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn lock_1<'a>(self) -> LockReturn<'a, 'context, B, ((), (), C), (A0, B, C0), O> where 'context: 'a, { lock_impl!(self, 1) } /// Lock the second element. The tuple becomes unusable until the returned /// guard is dropped. #[must_use] pub fn lock_mut_1(&mut self) -> ContextGuard<'_, B::Guard<'_>, ThreadKey> { lock_mut_impl!(self, 1) } /// Attempts to lock the second element without blocking. If successful, the /// tuple becomes unusable until the returned guard is dropped. If the element /// is already locked, `None` is returned. #[must_use] pub fn try_lock_mut_1(&mut self) -> Option, ThreadKey>> { try_lock_mut_impl!(self, 1) } } impl<'context, A, A0, B: RawLock + Sharable, C, C0, O> LockingTuple<'context, (A, B, C), (A0, B, C0), O> { /// Acquire a shared lock to the second element, and return a new tuple where /// the second element is inaccessible. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn read_1<'a>(self) -> ReadReturn<'a, 'context, B, ((), (), C), (A0, B, C0), O> where 'context: 'a, { read_impl!(self, 1) } /// Acquire a shared lock to the second element. The tuple becomes unusable /// until the returned guard is dropped. #[must_use] pub fn read_mut_1(&mut self) -> ContextGuard<'_, B::ReadGuard<'_>, ThreadKey> { read_mut_impl!(self, 1) } /// Attempts to acquire a shared lock the second element without blocking. If /// successful, the tuple becomes unusable until the returned guard is /// dropped. If the element is already exclusively locked, `None` is returned. #[must_use] pub fn try_read_mut_1(&mut self) -> Option, ThreadKey>> { try_read_mut_impl!(self, 1) } } impl<'context, A, A0, B, C, C0, O> LockingTuple<'context, (A, B, C), (A0, B, C0), O> { /// Consume the tuple, and return the second element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_1(self) -> RecurseReturn<'context, B, ((), (), C), (A0, B, C0), O> { recurse_impl!(self, 1) } /// Consume the tuple, and return the second element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_1_iter(self) -> RecurseIterReturn<'context, B, ((), (), C), (A0, B, C0), O> where &'context B: IntoIterator, { recurse_iter_impl!(self, 1) } } impl<'context, A, A0, B, B0, C: RawLock + Lockable, O> LockingTuple<'context, (A, B, C), (A0, B0, C), O> { /// Lock the third element, and return a new tuple where all elements are /// inaccessible. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn lock_2<'a>(self) -> LockReturn<'a, 'context, C, ((), (), ()), (A0, B0, C), O> where 'context: 'a, { lock_impl!(self, 2) } /// Lock the third element. The tuple becomes unusable until the returned /// guard is dropped. #[must_use] pub fn lock_mut_2(&mut self) -> ContextGuard<'_, C::Guard<'_>, ThreadKey> { lock_mut_impl!(self, 2) } /// Attempts to lock the third element without blocking. If successful, the /// tuple becomes unusable until the returned guard is dropped. If the element /// is already locked, `None` is returned. #[must_use] pub fn try_lock_mut_2(&mut self) -> Option, ThreadKey>> { try_lock_mut_impl!(self, 2) } } impl<'context, A, A0, B, B0, C: RawLock + Sharable, O> LockingTuple<'context, (A, B, C), (A0, B0, C), O> { /// Acquire a shared lock to the third element, and return a new tuple where /// the third element is inaccessible. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn read_2<'a>(self) -> ReadReturn<'a, 'context, C, ((), (), ()), (A0, B0, C), O> where 'context: 'a, { read_impl!(self, 2) } /// Acquire a shared lock to the third element. The tuple becomes unusable /// until the returned guard is dropped. #[must_use] pub fn read_mut_2(&mut self) -> ContextGuard<'_, C::ReadGuard<'_>, ThreadKey> { read_mut_impl!(self, 2) } /// Attempts to acquire a shared lock the third element without blocking. If /// successful, the tuple becomes unusable until the returned guard is /// dropped. If the element is already exclusively locked, `None` is returned. #[must_use] pub fn try_read_mut_2(&mut self) -> Option, ThreadKey>> { try_read_mut_impl!(self, 2) } } impl<'context, A, A0, B, B0, C, O> LockingTuple<'context, (A, B, C), (A0, B0, C), O> { /// Consume the tuple, and return the third element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_2(self) -> RecurseReturn<'context, C, ((), (), ()), (A0, B0, C), O> { recurse_impl!(self, 2) } /// Consume the tuple, and return the third element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_2_iter(self) -> RecurseIterReturn<'context, C, ((), (), ()), (A0, B0, C), O> where &'context C: IntoIterator, { recurse_iter_impl!(self, 2) } } impl<'context, A, B, B0, C, C0, D, D0, O> LockingTuple<'context, (A, B, C, D), (A, B0, C0, D0), O> { /// Consume the tuple, and return the first element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_0(self) -> RecurseReturn<'context, A, ((), B, C, D), (A, B0, C0, D0), O> { recurse_impl!(self, 0) } /// Consume the tuple, and return the first element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_0_iter(self) -> RecurseIterReturn<'context, A, ((), B, C, D), (A, B0, C0, D0), O> where &'context A: IntoIterator, { recurse_iter_impl!(self, 0) } } impl<'context, A, A0, B, C, C0, D, D0, O> LockingTuple<'context, (A, B, C, D), (A0, B, C0, D0), O> { /// Consume the tuple, and return the second element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_1(self) -> RecurseReturn<'context, B, ((), (), C, D), (A0, B, C0, D0), O> { recurse_impl!(self, 1) } /// Consume the tuple, and return the second element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_1_iter( self, ) -> RecurseIterReturn<'context, B, ((), (), C, D), (A0, B, C0, D0), O> where &'context B: IntoIterator, { recurse_iter_impl!(self, 1) } } impl<'context, A, A0, B, B0, C, D, D0, O> LockingTuple<'context, (A, B, C, D), (A0, B0, C, D0), O> { /// Consume the tuple, and return the third element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_2(self) -> RecurseReturn<'context, C, ((), (), (), D), (A0, B0, C, D0), O> { recurse_impl!(self, 2) } /// Consume the tuple, and return the third element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_2_iter( self, ) -> RecurseIterReturn<'context, C, ((), (), (), D), (A0, B0, C, D0), O> where &'context C: IntoIterator, { recurse_iter_impl!(self, 2) } } impl<'context, A, A0, B, B0, C, C0, D, O> LockingTuple<'context, (A, B, C, D), (A0, B0, C0, D), O> { /// Consume the tuple, and return the fourth element as a new tuple. #[must_use] // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_3(self) -> RecurseReturn<'context, D, ((), (), (), ()), (A0, B0, C0, D), O> { recurse_impl!(self, 3) } /// Consume the tuple, and return the first element as a locking iterator. // The type is impossible to refactor, and I already wrote this function, so no point in removing it #[expect(clippy::type_complexity)] pub fn recurse_3_iter( self, ) -> RecurseIterReturn<'context, D, ((), (), (), ()), (A0, B0, C0, D), O> where &'context D: IntoIterator, { recurse_iter_impl!(self, 3) } }