option_lock/
mutex.rs

1use core::{
2    fmt::{self, Debug, Formatter},
3    ops::{Deref, DerefMut},
4};
5
6#[cfg(feature = "alloc")]
7use alloc::sync::Arc;
8
9use super::{
10    error::{MutexLockError, OptionLockError, PoisonError},
11    lock::{OptionGuard, OptionLock},
12};
13
14#[cfg(feature = "alloc")]
15use super::arc::MutexGuardArc;
16
17/// An `OptionLock` with a guaranteed value.
18#[repr(transparent)]
19pub struct Mutex<T> {
20    pub(crate) inner: OptionLock<T>,
21}
22
23impl<T> Mutex<T> {
24    /// Create a new mutex instance.
25    pub const fn new(value: T) -> Self {
26        Self {
27            inner: OptionLock::new(value),
28        }
29    }
30
31    #[inline]
32    pub(crate) unsafe fn as_ptr(&self) -> *const T {
33        self.inner.as_ptr()
34    }
35
36    #[inline]
37    pub(crate) unsafe fn as_mut_ptr(&self) -> *mut T {
38        self.inner.as_mut_ptr()
39    }
40
41    /// Check if a guard is held.
42    #[inline]
43    pub fn is_locked(&self) -> bool {
44        self.inner.is_locked()
45    }
46
47    /// Check if the contained value was removed.
48    #[inline]
49    pub fn is_poisoned(&self) -> bool {
50        !self.inner.is_some()
51    }
52
53    /// Get a mutable reference to the contained value
54    pub fn get_mut(&mut self) -> &mut T {
55        unsafe { &mut *self.as_mut_ptr() }
56    }
57
58    /// Unwrap an owned mutex instance.
59    pub fn into_inner(self) -> Result<T, PoisonError> {
60        self.inner.into_inner().ok_or(PoisonError)
61    }
62
63    /// Try to acquire an exclusive lock around the contained value
64    #[inline]
65    pub fn try_lock(&self) -> Result<MutexGuard<'_, T>, MutexLockError> {
66        match self.inner.try_get() {
67            Ok(guard) => Ok(guard),
68            Err(OptionLockError::FillState) => Err(MutexLockError::Poisoned),
69            Err(OptionLockError::Unavailable) => Err(MutexLockError::Unavailable),
70        }
71    }
72
73    #[cfg(feature = "alloc")]
74    /// Try to acquire an exclusive lock for an `Arc<Mutex>`.
75    pub fn try_lock_arc(self: &Arc<Self>) -> Result<MutexGuardArc<T>, MutexLockError> {
76        self.try_lock()
77            .map(|guard| MutexGuardArc::new(self.clone(), guard))
78    }
79
80    /// In a spin loop, wait to acquire the mutex.
81    pub fn spin_lock(&self) -> Result<MutexGuard<'_, T>, PoisonError> {
82        let guard = self.inner.spin_lock();
83        if guard.is_none() {
84            Err(PoisonError)
85        } else {
86            Ok(MutexGuard::new(guard))
87        }
88    }
89}
90
91impl<T: Clone> Mutex<T> {
92    /// Try to clone the contained resource.
93    #[inline]
94    pub fn try_clone(&self) -> Result<T, MutexLockError> {
95        self.try_lock().map(|g| (*g).clone())
96    }
97}
98
99impl<T: Copy> Mutex<T> {
100    /// Try to copy the contained resource.
101    ///
102    /// On successful acquisition `Some(T)` is returned. If the lock
103    /// is currently held or the value is empty, then `None` is returned.
104    #[inline]
105    pub fn try_copy(&self) -> Result<T, MutexLockError> {
106        self.try_lock().map(|g| *g)
107    }
108}
109
110impl<T> Debug for Mutex<T> {
111    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
112        write!(f, "Mutex({:?})", &self.inner.state)
113    }
114}
115
116#[cfg(feature = "std")]
117impl<T> ::std::panic::RefUnwindSafe for Mutex<T> {}
118#[cfg(feature = "std")]
119impl<T> ::std::panic::UnwindSafe for Mutex<T> {}
120
121/// An exclusive guard for a filled [`OptionLock`]
122pub struct MutexGuard<'a, T>(OptionGuard<'a, T>);
123
124impl<'a, T> MutexGuard<'a, T> {
125    #[inline]
126    pub(crate) fn new(guard: OptionGuard<'a, T>) -> Self {
127        Self(guard)
128    }
129}
130
131impl<T> MutexGuard<'_, T> {
132    /// Take the value from the mutex. This will result in a `PoisonError` the
133    /// next time a lock is attempted.
134    pub fn extract(mut slf: Self) -> T {
135        slf.0.take().unwrap()
136    }
137
138    /// Replace the value in the lock, returning the previous value.
139    pub fn replace(slf: &mut Self, value: T) -> T {
140        slf.0.replace(value).unwrap()
141    }
142}
143
144impl<T> Deref for MutexGuard<'_, T> {
145    type Target = T;
146
147    fn deref(&self) -> &Self::Target {
148        self.0.as_ref().unwrap()
149    }
150}
151
152impl<T> DerefMut for MutexGuard<'_, T> {
153    fn deref_mut(&mut self) -> &mut Self::Target {
154        self.0.as_mut().unwrap()
155    }
156}
157
158impl<T: Debug> Debug for MutexGuard<'_, T> {
159    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
160        f.debug_tuple("MutexGuard").field(&**self).finish()
161    }
162}
163
164#[cfg(feature = "std")]
165impl<T> Drop for MutexGuard<'_, T> {
166    fn drop(&mut self) {
167        // Drop the contained value on a panic, because it may not have
168        // been left in a consistent state.
169        if self.0.is_some() && ::std::thread::panicking() {
170            self.0.take();
171        }
172    }
173}
174
175unsafe impl<T: Send> Send for MutexGuard<'_, T> {}
176unsafe impl<T: Sync> Sync for MutexGuard<'_, T> {}