summaryrefslogtreecommitdiff
path: root/src/context/tuple.rs
blob: d2a1b0d72403dc998f3e7974fea0e9d1db2a70f6 (plain)
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<C>(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, <Guarded as Lockable>::Guard<'a>, ThreadKey>,
	LockingTuple<'context, L, C, O>,
);

type TryLockReturn<'a, 'context, Guarded, L, C, O, This> =
	Result<LockReturn<'a, 'context, Guarded, L, C, O>, This>;

type ReadReturn<'a, 'context, Guarded, L, C, O> = (
	ContextGuard<'a, <Guarded as Sharable>::ReadGuard<'a>, ThreadKey>,
	LockingTuple<'context, L, C, O>,
);

type TryReadReturn<'a, 'context, Guarded, L, C, O, This> =
	Result<ReadReturn<'a, 'context, Guarded, L, C, O>, 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<T, C, Outer> 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<ContextGuard<'_, A::Guard<'_>, 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<ContextGuard<'_, A::ReadGuard<'_>, 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<ContextGuard<'_, A::Guard<'_>, 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<ContextGuard<'_, A::ReadGuard<'_>, 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, <A as Lockable>::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<ContextGuard<'_, B::Guard<'_>, 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<ContextGuard<'_, B::ReadGuard<'_>, 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<ContextGuard<'_, A::Guard<'_>, 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<ContextGuard<'_, A::ReadGuard<'_>, 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<ContextGuard<'_, B::Guard<'_>, 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<ContextGuard<'_, B::ReadGuard<'_>, 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<ContextGuard<'_, C::Guard<'_>, 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<ContextGuard<'_, C::ReadGuard<'_>, 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)
	}
}