use core::fmt::{self, Debug, Formatter};
use core::ops::{Deref, DerefMut};
use crate::cfg::atomic::AtomicBool;
use crate::inner::raw as inner;
use crate::relax::{Relax, RelaxWait};
#[cfg(test)]
use crate::test::{LockNew, LockThen, LockWithThen, TryLockThen, TryLockWithThen};
#[derive(Debug)]
#[repr(transparent)]
pub struct MutexNode {
inner: inner::MutexNode<AtomicBool>,
}
impl MutexNode {
#[must_use]
#[inline(always)]
pub const fn new() -> Self {
Self { inner: inner::MutexNode::new() }
}
}
#[cfg(not(tarpaulin_include))]
#[doc(hidden)]
impl Deref for MutexNode {
type Target = inner::MutexNode<AtomicBool>;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[doc(hidden)]
impl DerefMut for MutexNode {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[cfg(not(tarpaulin_include))]
impl Default for MutexNode {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
pub struct Mutex<T: ?Sized, R> {
pub(super) inner: inner::Mutex<T, AtomicBool, RelaxWait<R>>,
}
unsafe impl<T: ?Sized + Send, R> Send for Mutex<T, R> {}
unsafe impl<T: ?Sized + Send, R> Sync for Mutex<T, R> {}
impl<T, R> Mutex<T, R> {
#[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(crate) 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, R: Relax> Mutex<T, R> {
#[inline]
pub fn try_lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(Option<&mut T>) -> Ret,
{
self.try_lock_with_then(&mut MutexNode::new(), f)
}
#[inline]
pub fn try_lock_with_then<'a, F, Ret>(&'a self, node: &'a mut MutexNode, f: F) -> Ret
where
F: FnOnce(Option<&mut T>) -> Ret,
{
self.inner.try_lock_with_then(&mut node.inner, f)
}
#[inline]
pub fn lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(&mut T) -> Ret,
{
self.lock_with_then(&mut MutexNode::new(), f)
}
#[inline]
pub fn lock_with_then<'a, F, Ret>(&'a self, node: &'a mut MutexNode, f: F) -> Ret
where
F: FnOnce(&mut T) -> Ret,
{
self.inner.lock_with_then(&mut node.inner, f)
}
}
impl<T: ?Sized, R> Mutex<T, R> {
#[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, R> Default for Mutex<T, R> {
#[inline]
fn default() -> Self {
Self::new(Default::default())
}
}
impl<T, R> From<T> for Mutex<T, R> {
#[inline]
fn from(data: T) -> Self {
Self::new(data)
}
}
impl<T: ?Sized + Debug, R: Relax> Debug for Mutex<T, R> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[cfg(test)]
impl<T: ?Sized, R> LockNew for Mutex<T, R> {
type Target = T;
fn new(value: Self::Target) -> Self
where
Self::Target: Sized,
{
Self::new(value)
}
}
#[cfg(test)]
impl<T: ?Sized, R: Relax> LockWithThen for Mutex<T, R> {
type Node = MutexNode;
type Guard<'a>
= &'a mut Self::Target
where
Self: 'a,
Self::Target: 'a;
fn lock_with_then<F, Ret>(&self, node: &mut Self::Node, f: F) -> Ret
where
F: FnOnce(&mut Self::Target) -> Ret,
{
self.lock_with_then(node, f)
}
}
#[cfg(test)]
impl<T: ?Sized, R: Relax> TryLockWithThen for Mutex<T, R> {
fn try_lock_with_then<F, Ret>(&self, node: &mut Self::Node, f: F) -> Ret
where
F: FnOnce(Option<&mut Self::Target>) -> Ret,
{
self.try_lock_with_then(node, f)
}
fn is_locked(&self) -> bool {
self.is_locked()
}
}
#[cfg(test)]
impl<T: ?Sized, R: Relax> LockThen for Mutex<T, R> {
fn lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(&mut Self::Target) -> Ret,
{
self.lock_then(f)
}
}
#[cfg(test)]
impl<T: ?Sized, R: Relax> TryLockThen for Mutex<T, R> {
fn try_lock_then<F, Ret>(&self, f: F) -> Ret
where
F: FnOnce(Option<&mut Self::Target>) -> Ret,
{
self.try_lock_then(f)
}
}
#[cfg(all(not(loom), test))]
impl<T: ?Sized, R> crate::test::LockData for Mutex<T, R> {
fn into_inner(self) -> Self::Target
where
Self::Target: Sized,
{
self.into_inner()
}
fn get_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}
#[cfg(all(not(loom), test))]
mod test {
use crate::raw::yields;
use crate::test::tests;
type Mutex<T> = yields::Mutex<T>;
#[test]
fn node_waiter_drop_does_not_matter() {
tests::node_waiter_drop_does_not_matter::<super::AtomicBool>();
}
#[test]
fn lots_and_lots_lock_yield_backoff() {
tests::lots_and_lots_lock::<yields::backoff::Mutex<_>>();
}
#[test]
fn lots_and_lots_try_lock_yield_backoff() {
tests::lots_and_lots_try_lock::<yields::backoff::Mutex<_>>();
}
#[test]
fn lots_and_lots_mixed_lock_yield_backoff() {
tests::lots_and_lots_mixed_lock::<yields::backoff::Mutex<_>>();
}
#[test]
fn smoke() {
tests::smoke::<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::raw::yields::Mutex;
#[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<_>>();
}
}