use core::fmt::{self, Debug, Display, Formatter};
use crate::cfg::atomic::AtomicBool;
use crate::inner::barging as inner;
use crate::relax::{Relax, RelaxWait};
#[cfg(test)]
use crate::test::{LockNew, LockThen, LockWithThen, TryLockThen, TryLockWithThen};
#[cfg(all(loom, test))]
use crate::loom::{Guard, GuardDeref, GuardDerefMut};
#[cfg(all(loom, test))]
use crate::test::{AsDeref, AsDerefMut};
type MutexInner<T, Rs, Rq> = inner::Mutex<T, AtomicBool, RelaxWait<Rs>, RelaxWait<Rq>>;
pub struct Mutex<T: ?Sized, Rs, Rq> {
pub(super) inner: MutexInner<T, Rs, Rq>,
}
unsafe impl<T: ?Sized + Send, Rs, Rq> Send for Mutex<T, Rs, Rq> {}
unsafe impl<T: ?Sized + Send, Rs, Rq> Sync for Mutex<T, Rs, Rq> {}
impl<T, Rs, Rq> Mutex<T, Rs, Rq> {
#[cfg(not(all(loom, test)))]
#[inline]
pub const fn new(value: T) -> Self {
Self { inner: inner::Mutex::new(value) }
}
#[cfg(all(loom, test))]
#[cfg(not(tarpaulin_include))]
pub(super) fn new(value: T) -> Self {
Self { inner: inner::Mutex::new(value) }
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.inner.into_inner()
}
}
impl<T: ?Sized, Rs: Relax, Rq: Relax> Mutex<T, Rs, Rq> {
#[inline]
#[allow(clippy::non_minimal_cfg)]
pub fn lock(&self) -> MutexGuard<'_, T, Rs, Rq> {
#[cfg(not(feature = "thread_local"))]
{
self.lock_with_stack_queue_node()
}
#[cfg(any(feature = "thread_local"))]
{
self.lock_with_local_queue_node()
}
}
#[inline]
pub fn lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(MutexGuard<'_, T, Rs, Rq>) -> Ret,
{
f(self.lock())
}
#[cfg(any(test, not(feature = "thread_local")))]
fn lock_with_stack_queue_node(&self) -> MutexGuard<'_, T, Rs, Rq> {
self.inner.lock().into()
}
}
impl<T: ?Sized, Rs, Rq> Mutex<T, Rs, Rq> {
#[inline]
pub fn try_lock(&self) -> Option<MutexGuard<'_, T, Rs, Rq>> {
self.inner.try_lock().map(From::from)
}
#[inline]
pub fn try_lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(Option<MutexGuard<'_, T, Rs, Rq>>) -> Ret,
{
f(self.try_lock())
}
#[inline]
pub fn is_locked(&self) -> bool {
self.inner.is_locked()
}
#[cfg(not(all(loom, test)))]
#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
self.inner.get_mut()
}
}
impl<T: Default, Rs, Rq> Default for Mutex<T, Rs, Rq> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T, Rs, Rq> From<T> for Mutex<T, Rs, Rq> {
#[inline]
fn from(data: T) -> Self {
Self::new(data)
}
}
impl<T: ?Sized + Debug, Rs, Rq> Debug for Mutex<T, Rs, Rq> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[cfg(test)]
struct MutexStackNode<T: ?Sized, Rs, Rq>(Mutex<T, Rs, Rq>);
#[cfg(test)]
impl<T: Default, Rs, Rq> Default for MutexStackNode<T, Rs, Rq> {
fn default() -> Self {
Self(Mutex::default())
}
}
#[cfg(test)]
impl<T, Rs, Rq> From<T> for MutexStackNode<T, Rs, Rq> {
fn from(value: T) -> Self {
Self(Mutex::from(value))
}
}
#[cfg(test)]
impl<T: ?Sized + Debug, Rs, Rq> Debug for MutexStackNode<T, Rs, Rq> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
impl<T: ?Sized, Rs, Rq> LockNew for MutexStackNode<T, Rs, Rq> {
type Target = T;
fn new(value: Self::Target) -> Self
where
Self::Target: Sized,
{
Self(Mutex::new(value))
}
}
#[cfg(test)]
impl<T: ?Sized, Rs: Relax, Rq: Relax> LockWithThen for MutexStackNode<T, Rs, Rq> {
type Node = ();
type Guard<'a>
= MutexGuard<'a, T, Rs, Rq>
where
Self: 'a,
Self::Target: 'a;
fn lock_with_then<F, Ret>(&self, (): &mut Self::Node, f: F) -> Ret
where
F: FnOnce(MutexGuard<'_, T, Rs, Rq>) -> Ret,
{
f(self.0.lock_with_stack_queue_node())
}
}
#[cfg(test)]
impl<T: ?Sized, Rs: Relax, Rq: Relax> TryLockWithThen for MutexStackNode<T, Rs, Rq> {
fn try_lock_with_then<F, Ret>(&self, (): &mut Self::Node, f: F) -> Ret
where
F: FnOnce(Option<MutexGuard<'_, T, Rs, Rq>>) -> Ret,
{
self.0.try_lock_then(f)
}
fn is_locked(&self) -> bool {
self.0.is_locked()
}
}
#[cfg(all(not(loom), test))]
impl<T: ?Sized, Rs, Rq> crate::test::LockData for MutexStackNode<T, Rs, Rq> {
fn into_inner(self) -> Self::Target
where
Self::Target: Sized,
{
self.0.into_inner()
}
fn get_mut(&mut self) -> &mut Self::Target {
self.0.get_mut()
}
}
#[cfg(test)]
impl<T: ?Sized, Rs: Relax, Rq: Relax> LockThen for MutexStackNode<T, Rs, Rq> {
fn lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(MutexGuard<'_, T, Rs, Rq>) -> Ret,
{
self.0.lock_then(f)
}
}
#[cfg(test)]
impl<T: ?Sized, Rs: Relax, Rq: Relax> TryLockThen for MutexStackNode<T, Rs, Rq> {}
#[cfg(all(feature = "lock_api", not(loom)))]
unsafe impl<Rs: Relax, Rq: Relax> lock_api::RawMutex for Mutex<(), Rs, Rq> {
type GuardMarker = lock_api::GuardSend;
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = Self::new(());
#[inline]
fn lock(&self) {
core::mem::forget(Self::lock(self));
}
#[inline]
fn try_lock(&self) -> bool {
Self::try_lock(self).map(core::mem::forget).is_some()
}
#[inline]
unsafe fn unlock(&self) {
self.inner.unlock();
}
#[inline]
fn is_locked(&self) -> bool {
self.is_locked()
}
}
type GuardInner<'a, T, Rs, Rq> = inner::MutexGuard<'a, T, AtomicBool, RelaxWait<Rs>, RelaxWait<Rq>>;
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, T: ?Sized, Rs, Rq> {
inner: GuardInner<'a, T, Rs, Rq>,
}
unsafe impl<T: ?Sized + Send, Rs, Rq> Send for MutexGuard<'_, T, Rs, Rq> {}
unsafe impl<T: ?Sized + Sync, Rs, Rq> Sync for MutexGuard<'_, T, Rs, Rq> {}
#[doc(hidden)]
impl<'a, T: ?Sized, Rs, Rq> From<GuardInner<'a, T, Rs, Rq>> for MutexGuard<'a, T, Rs, Rq> {
fn from(inner: GuardInner<'a, T, Rs, Rq>) -> Self {
Self { inner }
}
}
impl<T: ?Sized + Debug, Rs, Rq> Debug for MutexGuard<'_, T, Rs, Rq> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T: ?Sized + Display, Rs, Rq> Display for MutexGuard<'_, T, Rs, Rq> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[cfg(not(all(loom, test)))]
impl<T: ?Sized, Rs, Rq> core::ops::Deref for MutexGuard<'_, T, Rs, Rq> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
&self.inner
}
}
#[cfg(not(all(loom, test)))]
impl<T: ?Sized, Rs, Rq> core::ops::DerefMut for MutexGuard<'_, T, Rs, Rq> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}
#[cfg(all(loom, test))]
#[cfg(not(tarpaulin_include))]
unsafe impl<T: ?Sized, Rs, Rq> Guard for MutexGuard<'_, T, Rs, Rq> {
type Target = T;
fn get(&self) -> &loom::cell::UnsafeCell<Self::Target> {
self.inner.get()
}
}
#[cfg(all(loom, test))]
#[cfg(not(tarpaulin_include))]
impl<T: ?Sized, Rs, Rq> AsDeref for MutexGuard<'_, T, Rs, Rq> {
type Target = T;
type Deref<'a>
= GuardDeref<'a, Self>
where
Self: 'a,
Self::Target: 'a;
fn as_deref(&self) -> Self::Deref<'_> {
self.get_ref()
}
}
#[cfg(all(loom, test))]
#[cfg(not(tarpaulin_include))]
impl<T: ?Sized, Rs, Rq> AsDerefMut for MutexGuard<'_, T, Rs, Rq> {
type DerefMut<'a>
= GuardDerefMut<'a, Self>
where
Self: 'a,
Self::Target: 'a;
fn as_deref_mut(&mut self) -> Self::DerefMut<'_> {
self.get_mut()
}
}
#[cfg(all(not(loom), test))]
mod test {
use crate::relax::Yield;
use crate::test::tests;
type Mutex<T> = super::MutexStackNode<T, Yield, Yield>;
#[test]
fn node_waiter_drop_does_not_matter() {
tests::node_waiter_drop_does_not_matter::<super::AtomicBool>();
}
#[test]
fn lots_and_lots_lock() {
tests::lots_and_lots_lock::<Mutex<_>>();
}
#[test]
fn lots_and_lots_try_lock() {
tests::lots_and_lots_try_lock::<Mutex<_>>();
}
#[test]
fn lots_and_lots_mixed_lock() {
tests::lots_and_lots_mixed_lock::<Mutex<_>>();
}
#[test]
fn smoke() {
tests::smoke::<Mutex<_>>();
}
#[test]
fn test_guard_debug_display() {
tests::test_guard_debug_display::<Mutex<_>>();
}
#[test]
fn test_mutex_debug() {
tests::test_mutex_debug::<Mutex<_>>();
}
#[test]
fn test_mutex_from() {
tests::test_mutex_from::<Mutex<_>>();
}
#[test]
fn test_mutex_default() {
tests::test_mutex_default::<Mutex<_>>();
}
#[test]
fn test_try_lock() {
tests::test_try_lock::<Mutex<_>>();
}
#[test]
fn test_into_inner() {
tests::test_into_inner::<Mutex<_>>();
}
#[test]
fn test_into_inner_drop() {
tests::test_into_inner_drop::<Mutex<_>>();
}
#[test]
fn test_get_mut() {
tests::test_get_mut::<Mutex<_>>();
}
#[test]
fn test_lock_arc_nested() {
tests::test_lock_arc_nested::<Mutex<_>, Mutex<_>>();
}
#[test]
fn test_acquire_more_than_one_lock() {
tests::test_acquire_more_than_one_lock::<Mutex<_>>();
}
#[test]
fn test_lock_arc_access_in_unwind() {
tests::test_lock_arc_access_in_unwind::<Mutex<_>>();
}
#[test]
fn test_lock_unsized() {
tests::test_lock_unsized::<Mutex<_>>();
}
}
#[cfg(all(loom, test))]
mod model {
use crate::loom::models;
use crate::relax::Yield;
type Mutex<T> = super::MutexStackNode<T, Yield, Yield>;
#[test]
fn try_lock_join() {
models::try_lock_join::<Mutex<_>>();
}
#[test]
fn lock_join() {
models::lock_join::<Mutex<_>>();
}
#[test]
fn mixed_lock_join() {
models::mixed_lock_join::<Mutex<_>>();
}
}