lock_free_static/
mutex.rs

1use core::{
2    cell::UnsafeCell,
3    mem::ManuallyDrop,
4    ops::{Deref, DerefMut},
5    panic::{RefUnwindSafe, UnwindSafe},
6    sync::atomic::{AtomicBool, Ordering},
7};
8
9/// Lock-free mutex.
10///
11/// Does not provide waiting mechanism.
12pub struct Mutex<T: ?Sized> {
13    locked: AtomicBool,
14    inner: UnsafeCell<T>,
15}
16
17unsafe impl<T: Send + ?Sized> Send for Mutex<T> {}
18unsafe impl<T: Send + ?Sized> Sync for Mutex<T> {}
19
20impl<T: ?Sized> UnwindSafe for Mutex<T> {}
21impl<T: ?Sized> RefUnwindSafe for Mutex<T> {}
22
23impl<T> Mutex<T> {
24    /// Creates a new mutex in an unlocked state ready for use.
25    pub const fn new(item: T) -> Self {
26        Self {
27            inner: UnsafeCell::new(item),
28            locked: AtomicBool::new(false),
29        }
30    }
31
32    /// Consumes this mutex, returning the underlying data.
33    pub fn into_inner(self) -> T {
34        debug_assert!(!self.locked.load(Ordering::Acquire));
35        self.inner.into_inner()
36    }
37}
38
39impl<T: Default> Default for Mutex<T> {
40    fn default() -> Self {
41        Self::new(T::default())
42    }
43}
44
45impl<T: ?Sized> Mutex<T> {
46    /// Returns a pointer to the underlying data.
47    pub fn get_ptr(&self) -> *mut T {
48        self.inner.get()
49    }
50
51    /// Returns a mutable reference to the underlying data.
52    pub fn get_mut(&mut self) -> &mut T {
53        debug_assert!(!self.locked.load(Ordering::Acquire));
54        self.inner.get_mut()
55    }
56
57    /// Attempts to acquire this lock.
58    ///
59    /// If the lock could not be acquired at this time, then `None` is returned.
60    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the guard is dropped.
61    pub fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
62        if self.locked.swap(true, Ordering::AcqRel) {
63            None
64        } else {
65            Some(MutexGuard { owner: self })
66        }
67    }
68}
69
70/// [`Mutex`] lock guard.
71///
72/// When it is dropped, the lock will be unlocked.
73pub struct MutexGuard<'a, T: ?Sized> {
74    owner: &'a Mutex<T>,
75}
76
77unsafe impl<'a, T: Sync + ?Sized> Send for MutexGuard<'a, T> {}
78unsafe impl<'a, T: Sync + ?Sized> Sync for MutexGuard<'a, T> {}
79
80impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
81    type Target = T;
82    fn deref(&self) -> &Self::Target {
83        unsafe { &*self.owner.get_ptr() }
84    }
85}
86impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
87    fn deref_mut(&mut self) -> &mut Self::Target {
88        unsafe { &mut *self.owner.get_ptr() }
89    }
90}
91
92impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
93    fn drop(&mut self) {
94        self.owner.locked.store(false, Ordering::Release);
95    }
96}
97
98impl<'a, T: ?Sized> MutexGuard<'a, T> {
99    /// Returns a mutable reference to the data protected by the mutex and consumes the guard.
100    ///
101    /// The mutex will remain in a locked state forever after this call.
102    pub fn leak(self) -> &'a mut T {
103        let this = ManuallyDrop::new(self);
104        unsafe { &mut *this.owner.get_ptr() }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::Mutex;
111
112    #[test]
113    fn try_lock() {
114        let mutex = Mutex::<i32>::new(123);
115
116        let mut guard = mutex.try_lock().unwrap();
117        assert_eq!(*guard, 123);
118        assert!(mutex.try_lock().is_none());
119        *guard = 321;
120        assert_eq!(*guard, 321);
121        drop(guard);
122
123        assert_eq!(*mutex.try_lock().unwrap(), 321);
124    }
125
126    #[test]
127    fn leak() {
128        let mutex = Mutex::<i32>::new(123);
129        let value_mut = mutex.try_lock().unwrap().leak();
130        assert_eq!(*value_mut, 123);
131        assert!(mutex.try_lock().is_none());
132        *value_mut = 321;
133        assert_eq!(*value_mut, 321);
134    }
135}