use core::cell::UnsafeCell;
use core::fmt;
use core::marker::PhantomData;
use core::mem;
use core::ops::{Deref, DerefMut};
use crate::guard::{ExclusiveGuardData, abort_on_panic};
#[cfg(feature = "arc_lock")]
use alloc::sync::Arc;
use core::mem::ManuallyDrop;
use core::ptr;
#[cfg(feature = "owning_ref")]
use owning_ref::StableAddress;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub unsafe trait RawMutex {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self;
type Guard;
fn lock(&self) -> Self::Guard;
fn try_lock(&self) -> Option<Self::Guard>;
unsafe fn unlock(&self, guard: Self::Guard);
fn is_locked(&self) -> bool;
}
pub unsafe trait RawMutexFair: RawMutex {
unsafe fn unlock_fair(&self, guard: Self::Guard);
unsafe fn bump(&self, guard: &mut Self::Guard) {
let state = unsafe { ptr::read(guard) };
defer!(abort_on_panic(|| unsafe { ptr::write(guard, self.lock()) }));
unsafe { self.unlock_fair(state) };
}
}
pub unsafe trait RawMutexTimed: RawMutex {
type Duration;
type Instant;
fn try_lock_for(&self, timeout: Self::Duration) -> Option<Self::Guard>;
fn try_lock_until(&self, timeout: Self::Instant) -> Option<Self::Guard>;
}
pub struct Mutex<R, T: ?Sized> {
raw: R,
data: UnsafeCell<T>,
}
unsafe impl<R: RawMutex + Sync, T: ?Sized + Send> Sync for Mutex<R, T> {}
impl<R: RawMutex, T> Mutex<R, T> {
#[inline]
pub const fn new(val: T) -> Mutex<R, T> {
Mutex {
raw: R::INIT,
data: UnsafeCell::new(val),
}
}
#[inline]
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
impl<R, T> Mutex<R, T> {
#[inline]
pub const fn from_raw(raw_mutex: R, val: T) -> Mutex<R, T> {
Mutex {
raw: raw_mutex,
data: UnsafeCell::new(val),
}
}
#[inline]
pub fn into_inner_with_raw(self) -> (R, T) {
(self.raw, self.data.into_inner())
}
}
impl<R: RawMutex, T: ?Sized> Mutex<R, T> {
#[inline]
pub unsafe fn make_guard_unchecked(&self, guard: R::Guard) -> MutexGuard<'_, R, T> {
MutexGuard {
mutex: self,
marker: PhantomData,
guard: ManuallyDrop::new(guard),
}
}
#[inline]
#[track_caller]
pub fn lock(&self) -> MutexGuard<'_, R, T> {
let guard = self.raw.lock();
unsafe { self.make_guard_unchecked(guard) }
}
#[inline]
#[track_caller]
pub fn try_lock(&self) -> Option<MutexGuard<'_, R, T>> {
if let Some(guard) = self.raw.try_lock() {
Some(unsafe { self.make_guard_unchecked(guard) })
} else {
None
}
}
#[inline]
pub const fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
#[inline]
#[track_caller]
pub fn is_locked(&self) -> bool {
self.raw.is_locked()
}
#[inline]
#[track_caller]
pub unsafe fn force_unlock(&self, guard: R::Guard) {
unsafe { self.raw.unlock(guard) };
}
#[inline]
pub unsafe fn raw(&self) -> &R {
&self.raw
}
#[inline]
pub const fn data_ptr(&self) -> *mut T {
self.data.get()
}
#[cfg(feature = "arc_lock")]
#[inline]
unsafe fn make_arc_guard_unchecked(self: &Arc<Self>, guard: R::Guard) -> ArcMutexGuard<R, T> {
ArcMutexGuard {
mutex: self.clone(),
data_marker: PhantomData,
guard: ManuallyDrop::new(guard),
}
}
#[cfg(feature = "arc_lock")]
#[inline]
#[track_caller]
pub fn lock_arc(self: &Arc<Self>) -> ArcMutexGuard<R, T> {
let guard = self.raw.lock();
unsafe { self.make_arc_guard_unchecked(guard) }
}
#[cfg(feature = "arc_lock")]
#[inline]
#[track_caller]
pub fn try_lock_arc(self: &Arc<Self>) -> Option<ArcMutexGuard<R, T>> {
if let Some(guard) = self.raw.try_lock() {
Some(unsafe { self.make_arc_guard_unchecked(guard) })
} else {
None
}
}
}
impl<R: RawMutexFair, T: ?Sized> Mutex<R, T> {
#[inline]
#[track_caller]
pub unsafe fn force_unlock_fair(&self, guard: R::Guard) {
unsafe { self.raw.unlock_fair(guard) };
}
}
impl<R: RawMutexTimed, T: ?Sized> Mutex<R, T> {
#[inline]
#[track_caller]
pub fn try_lock_for(&self, timeout: R::Duration) -> Option<MutexGuard<'_, R, T>> {
if let Some(guard) = self.raw.try_lock_for(timeout) {
Some(unsafe { self.make_guard_unchecked(guard) })
} else {
None
}
}
#[inline]
#[track_caller]
pub fn try_lock_until(&self, timeout: R::Instant) -> Option<MutexGuard<'_, R, T>> {
if let Some(guard) = self.raw.try_lock_until(timeout) {
Some(unsafe { self.make_guard_unchecked(guard) })
} else {
None
}
}
#[cfg(feature = "arc_lock")]
#[inline]
#[track_caller]
pub fn try_lock_arc_for(self: &Arc<Self>, timeout: R::Duration) -> Option<ArcMutexGuard<R, T>> {
if let Some(guard) = self.raw.try_lock_for(timeout) {
Some(unsafe { self.make_arc_guard_unchecked(guard) })
} else {
None
}
}
#[cfg(feature = "arc_lock")]
#[inline]
#[track_caller]
pub fn try_lock_arc_until(
self: &Arc<Self>,
timeout: R::Instant,
) -> Option<ArcMutexGuard<R, T>> {
if let Some(guard) = self.raw.try_lock_until(timeout) {
Some(unsafe { self.make_arc_guard_unchecked(guard) })
} else {
None
}
}
}
impl<R: RawMutex, T: Default> Default for Mutex<R, T> {
#[inline]
fn default() -> Mutex<R, T> {
Mutex::new(Default::default())
}
}
impl<R: RawMutex, T> From<T> for Mutex<R, T> {
#[inline]
fn from(t: T) -> Mutex<R, T> {
Mutex::new(t)
}
}
impl<R: RawMutex, T: ?Sized + fmt::Debug> fmt::Debug for Mutex<R, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.try_lock() {
Some(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
None => {
struct LockedPlaceholder;
impl fmt::Debug for LockedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
f.debug_struct("Mutex")
.field("data", &LockedPlaceholder)
.finish()
}
}
}
}
#[cfg(feature = "serde")]
impl<R, T> Serialize for Mutex<R, T>
where
R: RawMutex,
T: Serialize + ?Sized,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.lock().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, R, T> Deserialize<'de> for Mutex<R, T>
where
R: RawMutex,
T: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(deserializer).map(Mutex::new)
}
}
#[clippy::has_significant_drop]
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MutexGuard<'a, R: RawMutex, T: ?Sized> {
mutex: &'a Mutex<R, T>,
marker: PhantomData<&'a mut T>,
pub(crate) guard: ManuallyDrop<R::Guard>,
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> {
pub fn mutex(s: &Self) -> &'a Mutex<R, T> {
s.mutex
}
#[inline]
pub fn map<U: ?Sized, F>(s: Self, f: F) -> MappedMutexGuard<'a, R, U>
where
F: FnOnce(&mut T) -> &mut U,
{
let raw = &s.mutex.raw;
let data = f(unsafe { s.mutex.data.get().as_mut_unchecked() });
let guard = unsafe { ptr::read(&s.guard) };
mem::forget(s);
MappedMutexGuard {
raw,
data: ExclusiveGuardData::new(data),
guard,
}
}
#[inline]
pub fn try_map<U: ?Sized, F>(s: Self, f: F) -> Result<MappedMutexGuard<'a, R, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
{
let raw = &s.mutex.raw;
let Some(data) = f(unsafe { s.mutex.data.get().as_mut_unchecked() }) else {
return Err(s);
};
let guard = unsafe { ptr::read(&s.guard) };
mem::forget(s);
Ok(MappedMutexGuard {
raw,
data: ExclusiveGuardData::new(data),
guard,
})
}
#[inline]
pub fn try_map_or_err<U: ?Sized, F, E>(
s: Self,
f: F,
) -> Result<MappedMutexGuard<'a, R, U>, (Self, E)>
where
F: FnOnce(&mut T) -> Result<&mut U, E>,
{
let raw = &s.mutex.raw;
let data = match f(unsafe { s.mutex.data.get().as_mut_unchecked() }) {
Ok(data) => data,
Err(e) => return Err((s, e)),
};
let guard = unsafe { ptr::read(&s.guard) };
mem::forget(s);
Ok(MappedMutexGuard {
raw,
data: ExclusiveGuardData::new(data),
guard,
})
}
#[inline]
#[track_caller]
pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
where
F: FnOnce() -> U,
{
let state = unsafe { ManuallyDrop::take(&mut s.guard) };
defer!(abort_on_panic(
|| s.guard = ManuallyDrop::new(s.mutex.raw.lock())
));
unsafe { s.mutex.raw.unlock(state) };
f()
}
#[inline]
pub fn leak(s: Self) -> &'a mut T {
let r = unsafe { s.mutex.data.get().as_mut_unchecked() };
mem::forget(s);
r
}
}
impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MutexGuard<'a, R, T> {
#[inline]
#[track_caller]
pub fn unlock_fair(s: Self) {
let mut s = ManuallyDrop::new(s);
unsafe {
s.mutex.raw.unlock_fair(ManuallyDrop::take(&mut s.guard));
}
}
#[inline]
#[track_caller]
pub fn unlocked_fair<F, U>(s: &mut Self, f: F) -> U
where
F: FnOnce() -> U,
{
let state = unsafe { ManuallyDrop::take(&mut s.guard) };
defer!(abort_on_panic(
|| s.guard = ManuallyDrop::new(s.mutex.raw.lock())
));
unsafe { s.mutex.raw.unlock_fair(state) };
f()
}
#[inline]
#[track_caller]
pub fn bump(s: &mut Self) {
unsafe { s.mutex.raw.bump(&mut s.guard) };
}
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Deref for MutexGuard<'a, R, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.mutex.data.get().as_ref_unchecked() }
}
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> DerefMut for MutexGuard<'a, R, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.mutex.data.get().as_mut_unchecked() }
}
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Drop for MutexGuard<'a, R, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.mutex.raw.unlock(ManuallyDrop::take(&mut self.guard));
}
}
}
impl<'a, R: RawMutex + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for MutexGuard<'a, R, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display for MutexGuard<'a, R, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[cfg(feature = "owning_ref")]
unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MutexGuard<'a, R, T> {}
#[cfg(feature = "arc_lock")]
#[clippy::has_significant_drop]
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct ArcMutexGuard<R: RawMutex, T: ?Sized> {
guard: ManuallyDrop<R::Guard>,
mutex: Arc<Mutex<R, T>>,
data_marker: PhantomData<T>,
}
#[cfg(feature = "arc_lock")]
impl<R: RawMutex, T: ?Sized> ArcMutexGuard<R, T> {
#[inline]
pub fn mutex(s: &Self) -> &Arc<Mutex<R, T>> {
&s.mutex
}
#[inline]
#[track_caller]
pub fn into_arc(s: Self) -> Arc<Mutex<R, T>> {
let mut s = ManuallyDrop::new(s);
let mutex = unsafe { ptr::read(&s.mutex) };
let guard = unsafe { ManuallyDrop::take(&mut s.guard) };
unsafe { mutex.raw.unlock(guard) };
mutex
}
#[inline]
#[track_caller]
pub fn unlocked<F, U>(s: &mut Self, f: F) -> U
where
F: FnOnce() -> U,
{
let state = unsafe { ManuallyDrop::take(&mut s.guard) };
defer!(abort_on_panic(
|| s.guard = ManuallyDrop::new(s.mutex.raw.lock())
));
unsafe { s.mutex.raw.unlock(state) };
f()
}
}
#[cfg(feature = "arc_lock")]
impl<R: RawMutexFair, T: ?Sized> ArcMutexGuard<R, T> {
#[inline]
#[track_caller]
pub fn unlock_fair(s: Self) {
drop(Self::into_arc_fair(s));
}
#[inline]
pub fn into_arc_fair(s: Self) -> Arc<Mutex<R, T>> {
let mut s = ManuallyDrop::new(s);
let mutex = unsafe { ptr::read(&s.mutex) };
let guard = unsafe { ManuallyDrop::take(&mut s.guard) };
unsafe { mutex.raw.unlock_fair(guard) };
mutex
}
#[inline]
#[track_caller]
pub fn unlocked_fair<F, U>(s: &mut Self, f: F) -> U
where
F: FnOnce() -> U,
{
let state = unsafe { ManuallyDrop::take(&mut s.guard) };
defer!(abort_on_panic(
|| s.guard = ManuallyDrop::new(s.mutex.raw.lock())
));
unsafe { s.mutex.raw.unlock_fair(state) };
f()
}
#[inline]
#[track_caller]
pub fn bump(s: &mut Self) {
unsafe { s.mutex.raw.bump(&mut s.guard) };
}
}
#[cfg(feature = "arc_lock")]
impl<R: RawMutex, T: ?Sized> Deref for ArcMutexGuard<R, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.mutex.data.get().as_ref_unchecked() }
}
}
#[cfg(feature = "arc_lock")]
impl<R: RawMutex, T: ?Sized> DerefMut for ArcMutexGuard<R, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.mutex.data.get().as_mut_unchecked() }
}
}
#[cfg(feature = "arc_lock")]
impl<R: RawMutex, T: ?Sized> Drop for ArcMutexGuard<R, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.mutex.raw.unlock(ManuallyDrop::take(&mut self.guard));
}
}
}
#[clippy::has_significant_drop]
#[must_use = "if unused the Mutex will immediately unlock"]
pub struct MappedMutexGuard<'a, R: RawMutex, T: ?Sized + 'a> {
raw: &'a R,
data: ExclusiveGuardData<T>,
guard: ManuallyDrop<R::Guard>,
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> MappedMutexGuard<'a, R, T> {
#[inline]
pub fn map<U: ?Sized, F>(mut s: Self, f: F) -> MappedMutexGuard<'a, R, U>
where
F: FnOnce(&mut T) -> &mut U,
{
let raw = s.raw;
let data = ExclusiveGuardData::new(f(unsafe { s.data.as_mut() }));
let guard = unsafe { ptr::read(&s.guard) };
mem::forget(s);
MappedMutexGuard { raw, data, guard }
}
#[inline]
pub fn try_map<U: ?Sized, F>(mut s: Self, f: F) -> Result<MappedMutexGuard<'a, R, U>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
{
let raw = s.raw;
let Some(data) = f(unsafe { s.data.as_mut() }) else {
return Err(s);
};
let data = ExclusiveGuardData::new(data);
let guard = unsafe { ptr::read(&s.guard) };
mem::forget(s);
Ok(MappedMutexGuard { raw, data, guard })
}
#[inline]
pub fn try_map_or_err<U: ?Sized, F, E>(
mut s: Self,
f: F,
) -> Result<MappedMutexGuard<'a, R, U>, (Self, E)>
where
F: FnOnce(&mut T) -> Result<&mut U, E>,
{
let raw = s.raw;
let data = match f(unsafe { s.data.as_mut() }) {
Ok(data) => data,
Err(e) => return Err((s, e)),
};
let data = ExclusiveGuardData::new(data);
let guard = unsafe { ptr::read(&s.guard) };
mem::forget(s);
Ok(MappedMutexGuard { raw, data, guard })
}
}
impl<'a, R: RawMutexFair + 'a, T: ?Sized + 'a> MappedMutexGuard<'a, R, T> {
#[inline]
#[track_caller]
pub fn unlock_fair(s: Self) {
let mut s = ManuallyDrop::new(s);
unsafe {
s.raw.unlock_fair(ManuallyDrop::take(&mut s.guard));
}
}
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Deref for MappedMutexGuard<'a, R, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.data.as_ref() }
}
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> DerefMut for MappedMutexGuard<'a, R, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> Drop for MappedMutexGuard<'a, R, T> {
#[inline]
fn drop(&mut self) {
unsafe {
self.raw.unlock(ManuallyDrop::take(&mut self.guard));
}
}
}
impl<'a, R: RawMutex + 'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for MappedMutexGuard<'a, R, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<'a, R: RawMutex + 'a, T: fmt::Display + ?Sized + 'a> fmt::Display
for MappedMutexGuard<'a, R, T>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
#[cfg(feature = "owning_ref")]
unsafe impl<'a, R: RawMutex + 'a, T: ?Sized + 'a> StableAddress for MappedMutexGuard<'a, R, T> {}