try_mutex/
lib.rs

1//! Provides a simple mutex that does not support blocking or poisoning, but is
2//! faster and simpler than the mutex in stdlib.
3
4#![no_std]
5
6use core::cell::UnsafeCell;
7use core::convert::From;
8use core::fmt;
9use core::fmt::{Debug, Display};
10use core::marker::PhantomData;
11use core::ops::{Deref, DerefMut};
12use core::panic::{RefUnwindSafe, UnwindSafe};
13use core::sync::atomic::{AtomicBool, Ordering};
14
15/// A mutual exclusion primitive that does not support blocking or poisoning.
16/// This results in a simpler and faster implementation.
17pub struct TryMutex<T> {
18    data: UnsafeCell<T>,
19    locked: AtomicBool,
20}
21
22impl<T> TryMutex<T> {
23    /// Create a new mutex in unlocked state.
24    #[inline]
25    pub const fn new(t: T) -> Self {
26        TryMutex {
27            data: UnsafeCell::new(t),
28            locked: AtomicBool::new(false),
29        }
30    }
31
32    /// Attemps to acquire a lock on this mutex. If this mutex is currently
33    /// locked, `None` is returned. Otherwise a RAII guard is returned. The lock
34    /// will be unlocked when the guard is dropped.
35    #[inline]
36    pub fn try_lock(&self) -> Option<TryMutexGuard<'_, T>> {
37        self.locked
38            .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
39            .ok()
40            .map(|_| TryMutexGuard {
41                lock: self,
42                notsend: PhantomData,
43            })
44    }
45
46    /// Consumes this mutex, returning the underlying data.
47    #[inline]
48    pub fn into_inner(self) -> T {
49        self.data.into_inner()
50    }
51
52    /// Retrieve a mutable reference to the underlying data. Since this mutably
53    /// borrows the mutex, no actual locking needs to take place.
54    #[inline]
55    pub fn get_mut(&mut self) -> &mut T {
56        unsafe { &mut *self.data.get() }
57    }
58}
59
60impl<T: Default> Default for TryMutex<T> {
61    fn default() -> Self {
62        Self::new(T::default())
63    }
64}
65
66impl<T: Debug> Debug for TryMutex<T> {
67    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68        if let Some(guard) = self.try_lock() {
69            f.debug_struct("TryMutex").field("data", &*guard).finish()
70        } else {
71            struct LockedPlaceholder;
72            impl fmt::Debug for LockedPlaceholder {
73                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74                    f.write_str("<locked>")
75                }
76            }
77
78            f.debug_struct("TryMutex")
79                .field("data", &LockedPlaceholder)
80                .finish()
81        }
82    }
83}
84
85/// A RAII scoped lock on a `TryMutex`. When this this structure is dropped, the
86/// mutex will be unlocked.
87pub struct TryMutexGuard<'a, T: 'a> {
88    lock: &'a TryMutex<T>,
89    notsend: PhantomData<*mut T>,
90}
91
92impl<'a, T> Deref for TryMutexGuard<'a, T> {
93    type Target = T;
94
95    fn deref(&self) -> &T {
96        unsafe { &*self.lock.data.get() }
97    }
98}
99
100impl<'a, T> DerefMut for TryMutexGuard<'a, T> {
101    fn deref_mut(&mut self) -> &mut T {
102        unsafe { &mut *self.lock.data.get() }
103    }
104}
105
106impl<'a, T> Drop for TryMutexGuard<'a, T> {
107    fn drop(&mut self) {
108        self.lock.locked.store(false, Ordering::Release);
109    }
110}
111
112impl<'a, T: Debug> Debug for TryMutexGuard<'a, T> {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        f.debug_struct("TryMutexGuard")
115            .field("data", &**self)
116            .finish()
117    }
118}
119
120impl<'a, T: Display> Display for TryMutexGuard<'a, T> {
121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122        (**self).fmt(f)
123    }
124}
125
126impl<T> UnwindSafe for TryMutex<T> {}
127impl<T> RefUnwindSafe for TryMutex<T> {}
128unsafe impl<T: Send> Send for TryMutex<T> {}
129unsafe impl<T: Send> Sync for TryMutex<T> {}
130unsafe impl<'a, T: Sync> Sync for TryMutexGuard<'a, T> {}
131unsafe impl<'a, T: Send> Send for TryMutexGuard<'a, T> {}
132
133impl<T> From<T> for TryMutex<T> {
134    fn from(t: T) -> Self {
135        TryMutex::new(t)
136    }
137}