use core::{
fmt::{self, Debug, Formatter},
ops::{Deref, DerefMut},
};
#[cfg(feature = "alloc")]
use alloc::sync::Arc;
use super::{
error::{MutexLockError, OptionLockError, PoisonError},
lock::{OptionGuard, OptionLock},
};
#[cfg(feature = "alloc")]
use super::arc::MutexGuardArc;
#[repr(transparent)]
pub struct Mutex<T> {
pub(crate) inner: OptionLock<T>,
}
impl<T> Mutex<T> {
pub const fn new(value: T) -> Self {
Self {
inner: OptionLock::new(value),
}
}
#[inline]
pub(crate) unsafe fn as_ptr(&self) -> *const T {
self.inner.as_ptr()
}
#[inline]
pub(crate) unsafe fn as_mut_ptr(&self) -> *mut T {
self.inner.as_mut_ptr()
}
#[inline]
pub fn is_locked(&self) -> bool {
self.inner.is_locked()
}
#[inline]
pub fn is_poisoned(&self) -> bool {
!self.inner.is_some()
}
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.as_mut_ptr() }
}
pub fn into_inner(self) -> Result<T, PoisonError> {
self.inner.into_inner().ok_or(PoisonError)
}
#[inline]
pub fn try_lock(&self) -> Result<MutexGuard<'_, T>, MutexLockError> {
match self.inner.try_get() {
Ok(guard) => Ok(guard),
Err(OptionLockError::FillState) => Err(MutexLockError::Poisoned),
Err(OptionLockError::Unavailable) => Err(MutexLockError::Unavailable),
}
}
#[cfg(feature = "alloc")]
pub fn try_lock_arc(self: &Arc<Self>) -> Result<MutexGuardArc<T>, MutexLockError> {
self.try_lock()
.map(|guard| MutexGuardArc::new(self.clone(), guard))
}
pub fn spin_lock(&self) -> Result<MutexGuard<'_, T>, PoisonError> {
let guard = self.inner.spin_lock();
if guard.is_none() {
Err(PoisonError)
} else {
Ok(MutexGuard::new(guard))
}
}
}
impl<T: Clone> Mutex<T> {
#[inline]
pub fn try_clone(&self) -> Result<T, MutexLockError> {
self.try_lock().map(|g| (*g).clone())
}
}
impl<T: Copy> Mutex<T> {
#[inline]
pub fn try_copy(&self) -> Result<T, MutexLockError> {
self.try_lock().map(|g| *g)
}
}
impl<T> Debug for Mutex<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Mutex({:?})", &self.inner.state)
}
}
#[cfg(feature = "std")]
impl<T> ::std::panic::RefUnwindSafe for Mutex<T> {}
#[cfg(feature = "std")]
impl<T> ::std::panic::UnwindSafe for Mutex<T> {}
pub struct MutexGuard<'a, T>(OptionGuard<'a, T>);
impl<'a, T> MutexGuard<'a, T> {
#[inline]
pub(crate) fn new(guard: OptionGuard<'a, T>) -> Self {
Self(guard)
}
}
impl<T> MutexGuard<'_, T> {
pub fn extract(mut slf: Self) -> T {
slf.0.take().unwrap()
}
pub fn replace(slf: &mut Self, value: T) -> T {
slf.0.replace(value).unwrap()
}
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0.as_ref().unwrap()
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.as_mut().unwrap()
}
}
impl<T: Debug> Debug for MutexGuard<'_, T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("MutexGuard").field(&**self).finish()
}
}
#[cfg(feature = "std")]
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
if self.0.is_some() && ::std::thread::panicking() {
self.0.take();
}
}
}
unsafe impl<T: Send> Send for MutexGuard<'_, T> {}
unsafe impl<T: Sync> Sync for MutexGuard<'_, T> {}