use core::{
cell::UnsafeCell,
fmt,
marker::PhantomData,
mem::{self, ManuallyDrop},
ops::{Deref, DerefMut},
ptr::NonNull,
time::Duration,
};
use crate::{
sync::{
nonpoison::{TryLockError, TryLockResult},
RawMutex, RawMutexTimed,
},
sys::sync as sys,
time::Instant,
};
type DefaultMutex = cfg_select! {
feature = "kernel" => sys::Mutex,
pbp => sys::LwMutex,
_ => sys::SemaMutex,
};
pub struct Mutex<T: ?Sized, M = DefaultMutex> {
inner: M,
data: UnsafeCell<T>,
}
unsafe impl<T: ?Sized + Send, M> Send for Mutex<T, M> {}
unsafe impl<T: ?Sized + Send, M> Sync for Mutex<T, M> {}
impl<T: ?Sized, M> core::panic::UnwindSafe for Mutex<T, M> {}
impl<T: ?Sized, M> core::panic::RefUnwindSafe for Mutex<T, M> {}
#[must_use = "if unused the Mutex will immediately unlock"]
#[clippy::has_significant_drop]
pub struct MutexGuard<'a, T: ?Sized + 'a, M: RawMutex = DefaultMutex> {
lock: &'a Mutex<T, M>,
}
impl<T: ?Sized, M: RawMutex> !Send for MutexGuard<'_, T, M> {}
unsafe impl<T: ?Sized + Sync, M: RawMutex> Sync for MutexGuard<'_, T, M> {}
#[must_use = "if unused the Mutex will immediately unlock"]
#[clippy::has_significant_drop]
pub struct MappedMutexGuard<'a, T: ?Sized + 'a, M: RawMutex = DefaultMutex> {
data: NonNull<T>,
inner: &'a M,
_variance: PhantomData<&'a mut T>,
}
impl<T: ?Sized, M: RawMutex> !Send for MappedMutexGuard<'_, T, M> {}
unsafe impl<T: ?Sized + Sync, M: RawMutex> Sync for MappedMutexGuard<'_, T, M> {}
impl<T> Mutex<T> {
#[inline]
pub const fn new(t: T) -> Mutex<T> {
Mutex {
inner: DefaultMutex::new(),
data: UnsafeCell::new(t),
}
}
}
impl<T, M: RawMutex> Mutex<T, M> {
#[inline]
pub const fn new_with(value: T, raw_mutex: M) -> Self {
Self {
inner: raw_mutex,
data: UnsafeCell::new(value),
}
}
pub fn get_cloned(&self) -> T
where
T: Clone,
{
let guard = self.lock();
(*guard).clone()
}
pub fn set(&self, value: T) {
if mem::needs_drop::<T>() {
let res = self.replace(value);
drop(res);
} else {
let mut guard = self.lock();
*guard = value;
}
}
pub fn replace(&self, value: T) -> T {
let mut guard = self.lock();
mem::replace(&mut *guard, value)
}
}
impl<T: ?Sized, M: RawMutex> Mutex<T, M> {
pub fn lock(&self) -> MutexGuard<'_, T, M> {
self.inner.lock();
unsafe { MutexGuard::new(self) }
}
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T, M>> {
if self.inner.try_lock() {
Ok(unsafe { MutexGuard::new(self) })
} else {
Err(TryLockError::WouldBlock)
}
}
pub fn into_inner(self) -> T
where
T: Sized,
{
self.data.into_inner()
}
pub fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
pub const fn data_ptr(&self) -> *mut T {
self.data.get()
}
pub fn with_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
f(&mut self.lock())
}
}
impl<T: ?Sized, M: RawMutexTimed> Mutex<T, M> {
#[inline]
#[track_caller]
pub fn try_lock_for(&self, timeout: Duration) -> Option<MutexGuard<'_, T, M>> {
if self.inner.try_lock_for(timeout) {
Some(unsafe { MutexGuard::new(self) })
} else {
None
}
}
#[inline]
#[track_caller]
pub fn try_lock_until(&self, timeout: Instant) -> Option<MutexGuard<'_, T, M>> {
if self.inner.try_lock_until(timeout) {
Some(unsafe { MutexGuard::new(self) })
} else {
None
}
}
}
impl<T> From<T> for Mutex<T> {
fn from(t: T) -> Self {
Mutex::new(t)
}
}
impl<T> Default for Mutex<T>
where
T: Default,
{
fn default() -> Mutex<T> {
Mutex::new(Default::default())
}
}
impl<T: ?Sized + fmt::Debug, M: RawMutex> fmt::Debug for Mutex<T, M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("Mutex");
match self.try_lock() {
Ok(guard) => {
d.field("data", &&*guard);
},
Err(TryLockError::WouldBlock) => {
d.field("data", &format_args!("<locked>"));
},
}
d.finish_non_exhaustive()
}
}
impl<'mutex, T: ?Sized, M: RawMutex> MutexGuard<'mutex, T, M> {
unsafe fn new(lock: &'mutex Mutex<T, M>) -> MutexGuard<'mutex, T, M> {
MutexGuard { lock }
}
}
impl<T: ?Sized, M: RawMutex> Deref for MutexGuard<'_, T, M> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized, M: RawMutex> DerefMut for MutexGuard<'_, T, M> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T: ?Sized, M: RawMutex> Drop for MutexGuard<'_, T, M> {
#[inline]
fn drop(&mut self) {
unsafe {
self.lock.inner.unlock();
}
}
}
impl<T, M> fmt::Debug for MutexGuard<'_, T, M>
where
T: ?Sized + fmt::Debug,
M: RawMutex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T, M> fmt::Display for MutexGuard<'_, T, M>
where
T: ?Sized + fmt::Display,
M: RawMutex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
pub fn guard_lock<'a, T, M>(guard: &MutexGuard<'a, T, M>) -> &'a M
where
T: ?Sized,
M: RawMutex,
{
&guard.lock.inner
}
impl<'a, T: ?Sized, M: RawMutex> MutexGuard<'a, T, M> {
pub fn map<U, F>(orig: Self, f: F) -> MappedMutexGuard<'a, U, M>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard {
data,
inner: &orig.lock.inner,
_variance: PhantomData,
}
}
#[doc(alias = "filter_map")]
pub fn try_map<U, F>(orig: Self, f: F) -> Result<MappedMutexGuard<'a, U, M>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
U: ?Sized,
{
match f(unsafe { &mut *orig.lock.data.get() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard {
data,
inner: &orig.lock.inner,
_variance: PhantomData,
})
},
None => Err(orig),
}
}
}
impl<T: ?Sized, M: RawMutex> Deref for MappedMutexGuard<'_, T, M> {
type Target = T;
fn deref(&self) -> &T {
unsafe { self.data.as_ref() }
}
}
impl<T: ?Sized, M: RawMutex> DerefMut for MappedMutexGuard<'_, T, M> {
fn deref_mut(&mut self) -> &mut T {
unsafe { self.data.as_mut() }
}
}
impl<T: ?Sized, M: RawMutex> Drop for MappedMutexGuard<'_, T, M> {
#[inline]
fn drop(&mut self) {
unsafe {
self.inner.unlock();
}
}
}
impl<T, M> fmt::Debug for MappedMutexGuard<'_, T, M>
where
T: ?Sized + fmt::Debug,
M: RawMutex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T, M> fmt::Display for MappedMutexGuard<'_, T, M>
where
T: ?Sized + fmt::Display,
M: RawMutex,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<'a, T: ?Sized, M: RawMutex> MappedMutexGuard<'a, T, M> {
pub fn map<U, F>(mut orig: Self, f: F) -> MappedMutexGuard<'a, U, M>
where
F: FnOnce(&mut T) -> &mut U,
U: ?Sized,
{
let data = NonNull::from(f(unsafe { orig.data.as_mut() }));
let orig = ManuallyDrop::new(orig);
MappedMutexGuard {
data,
inner: orig.inner,
_variance: PhantomData,
}
}
#[doc(alias = "filter_map")]
pub fn try_map<U, F>(mut orig: Self, f: F) -> Result<MappedMutexGuard<'a, U, M>, Self>
where
F: FnOnce(&mut T) -> Option<&mut U>,
U: ?Sized,
{
match f(unsafe { orig.data.as_mut() }) {
Some(data) => {
let data = NonNull::from(data);
let orig = ManuallyDrop::new(orig);
Ok(MappedMutexGuard {
data,
inner: orig.inner,
_variance: PhantomData,
})
},
None => Err(orig),
}
}
}