use std::fmt;
use std::ops::Deref;
use std::ops::DerefMut;
use std::sync;
use std::sync::LockResult;
use std::sync::OnceState;
use std::sync::PoisonError;
use std::sync::TryLockError;
use std::sync::TryLockResult;
use std::sync::WaitTimeoutResult;
use std::time::Duration;
use crate::BorrowedMutex;
use crate::LazyMutexId;
use crate::util::PrivateTraced;
#[cfg(has_std__sync__LazyLock)]
pub use lazy_lock::LazyLock;
#[cfg(has_std__sync__LazyLock)]
mod lazy_lock;
#[derive(Debug, Default)]
pub struct Mutex<T: ?Sized> {
id: LazyMutexId,
inner: sync::Mutex<T>,
}
pub struct MutexGuard<'a, T: ?Sized> {
inner: sync::MutexGuard<'a, T>,
_mutex: BorrowedMutex<'a>,
}
fn map_lockresult<T, I, F>(result: LockResult<I>, mapper: F) -> LockResult<T>
where
F: FnOnce(I) -> T,
{
match result {
Ok(inner) => Ok(mapper(inner)),
Err(poisoned) => Err(PoisonError::new(mapper(poisoned.into_inner()))),
}
}
fn map_trylockresult<T, I, F>(result: TryLockResult<I>, mapper: F) -> TryLockResult<T>
where
F: FnOnce(I) -> T,
{
match result {
Ok(inner) => Ok(mapper(inner)),
Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(TryLockError::Poisoned(poisoned)) => {
Err(PoisonError::new(mapper(poisoned.into_inner())).into())
}
}
}
impl<T> Mutex<T> {
pub const fn new(t: T) -> Self {
Self {
inner: sync::Mutex::new(t),
id: LazyMutexId::new(),
}
}
}
impl<T: ?Sized> Mutex<T> {
#[track_caller]
pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
let mutex = self.id.get_borrowed();
let result = self.inner.lock();
let mapper = |guard| MutexGuard {
_mutex: mutex,
inner: guard,
};
map_lockresult(result, mapper)
}
#[track_caller]
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
let mutex = self.id.get_borrowed();
let result = self.inner.try_lock();
let mapper = |guard| MutexGuard {
_mutex: mutex,
inner: guard,
};
map_trylockresult(result, mapper)
}
pub fn is_poisoned(&self) -> bool {
self.inner.is_poisoned()
}
pub fn get_mut(&mut self) -> LockResult<&mut T> {
self.inner.get_mut()
}
pub fn into_inner(self) -> LockResult<T>
where
T: Sized,
{
self.inner.into_inner()
}
}
impl<T: ?Sized> PrivateTraced for Mutex<T> {
fn get_id(&self) -> &crate::MutexId {
&self.id
}
}
impl<T> From<T> for Mutex<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}
impl<T: ?Sized> Deref for MutexGuard<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for MutexGuard<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<T: fmt::Display + ?Sized> fmt::Display for MutexGuard<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[derive(Debug, Default)]
pub struct Condvar(sync::Condvar);
impl Condvar {
pub const fn new() -> Self {
Self(sync::Condvar::new())
}
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
let MutexGuard { _mutex, inner } = guard;
map_lockresult(self.0.wait(inner), |inner| MutexGuard { _mutex, inner })
}
pub fn wait_while<'a, T, F>(
&self,
guard: MutexGuard<'a, T>,
condition: F,
) -> LockResult<MutexGuard<'a, T>>
where
F: FnMut(&mut T) -> bool,
{
let MutexGuard { _mutex, inner } = guard;
map_lockresult(self.0.wait_while(inner, condition), |inner| MutexGuard {
_mutex,
inner,
})
}
pub fn wait_timeout<'a, T>(
&self,
guard: MutexGuard<'a, T>,
dur: Duration,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
let MutexGuard { _mutex, inner } = guard;
map_lockresult(self.0.wait_timeout(inner, dur), |(inner, result)| {
(MutexGuard { _mutex, inner }, result)
})
}
pub fn wait_timeout_while<'a, T, F>(
&self,
guard: MutexGuard<'a, T>,
dur: Duration,
condition: F,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
where
F: FnMut(&mut T) -> bool,
{
let MutexGuard { _mutex, inner } = guard;
map_lockresult(
self.0.wait_timeout_while(inner, dur, condition),
|(inner, result)| (MutexGuard { _mutex, inner }, result),
)
}
pub fn notify_one(&self) {
self.0.notify_one();
}
pub fn notify_all(&self) {
self.0.notify_all();
}
}
#[derive(Debug, Default)]
pub struct RwLock<T: ?Sized> {
id: LazyMutexId,
inner: sync::RwLock<T>,
}
pub struct TracingRwLockGuard<'a, L> {
inner: L,
_mutex: BorrowedMutex<'a>,
}
pub type RwLockReadGuard<'a, T> = TracingRwLockGuard<'a, sync::RwLockReadGuard<'a, T>>;
pub type RwLockWriteGuard<'a, T> = TracingRwLockGuard<'a, sync::RwLockWriteGuard<'a, T>>;
impl<T> RwLock<T> {
pub const fn new(t: T) -> Self {
Self {
inner: sync::RwLock::new(t),
id: LazyMutexId::new(),
}
}
}
impl<T: ?Sized> RwLock<T> {
#[track_caller]
pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
let mutex = self.id.get_borrowed();
let result = self.inner.read();
map_lockresult(result, |inner| TracingRwLockGuard {
inner,
_mutex: mutex,
})
}
#[track_caller]
pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
let mutex = self.id.get_borrowed();
let result = self.inner.write();
map_lockresult(result, |inner| TracingRwLockGuard {
inner,
_mutex: mutex,
})
}
#[track_caller]
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
let mutex = self.id.get_borrowed();
let result = self.inner.try_read();
map_trylockresult(result, |inner| TracingRwLockGuard {
inner,
_mutex: mutex,
})
}
#[track_caller]
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
let mutex = self.id.get_borrowed();
let result = self.inner.try_write();
map_trylockresult(result, |inner| TracingRwLockGuard {
inner,
_mutex: mutex,
})
}
pub fn get_mut(&mut self) -> LockResult<&mut T> {
self.inner.get_mut()
}
pub fn into_inner(self) -> LockResult<T>
where
T: Sized,
{
self.inner.into_inner()
}
}
impl<T: ?Sized> PrivateTraced for RwLock<T> {
fn get_id(&self) -> &crate::MutexId {
&self.id
}
}
impl<T> From<T> for RwLock<T> {
fn from(t: T) -> Self {
Self::new(t)
}
}
impl<L, T> Deref for TracingRwLockGuard<'_, L>
where
T: ?Sized,
L: Deref<Target = T>,
{
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.inner.deref()
}
}
impl<L, T> DerefMut for TracingRwLockGuard<'_, L>
where
T: ?Sized,
L: Deref<Target = T> + DerefMut,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.deref_mut()
}
}
impl<L> fmt::Debug for TracingRwLockGuard<'_, L>
where
L: fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
impl<L> fmt::Display for TracingRwLockGuard<'_, L>
where
L: fmt::Display,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.inner.fmt(f)
}
}
#[derive(Debug)]
pub struct Once {
inner: sync::Once,
mutex_id: LazyMutexId,
}
#[allow(clippy::new_without_default)]
impl Once {
pub const fn new() -> Self {
Self {
inner: sync::Once::new(),
mutex_id: LazyMutexId::new(),
}
}
pub fn call_once<F>(&self, f: F)
where
F: FnOnce(),
{
self.mutex_id.with_held(|| self.inner.call_once(f))
}
pub fn call_once_force<F>(&self, f: F)
where
F: FnOnce(&OnceState),
{
self.mutex_id.with_held(|| self.inner.call_once_force(f))
}
pub fn is_completed(&self) -> bool {
self.inner.is_completed()
}
}
impl PrivateTraced for Once {
fn get_id(&self) -> &crate::MutexId {
&self.mutex_id
}
}
#[derive(Debug)]
pub struct OnceLock<T> {
id: LazyMutexId,
inner: sync::OnceLock<T>,
}
impl<T> OnceLock<T> {
pub const fn new() -> Self {
Self {
id: LazyMutexId::new(),
inner: sync::OnceLock::new(),
}
}
#[inline]
pub fn get(&self) -> Option<&T> {
self.inner.get()
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut T> {
self.inner.get_mut()
}
pub fn set(&self, value: T) -> Result<(), T> {
self.id.with_held(|| self.inner.set(value))
}
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
self.id.with_held(|| self.inner.get_or_init(f))
}
#[inline]
pub fn take(&mut self) -> Option<T> {
self.inner.take()
}
#[inline]
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
}
impl<T> PrivateTraced for OnceLock<T> {
fn get_id(&self) -> &crate::MutexId {
&self.id
}
}
impl<T> Default for OnceLock<T> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<T: PartialEq> PartialEq for OnceLock<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T: Eq> Eq for OnceLock<T> {}
impl<T: Clone> Clone for OnceLock<T> {
fn clone(&self) -> Self {
Self {
id: LazyMutexId::new(),
inner: self.inner.clone(),
}
}
}
impl<T> From<T> for OnceLock<T> {
#[inline]
fn from(value: T) -> Self {
Self {
id: LazyMutexId::new(),
inner: sync::OnceLock::from(value),
}
}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::thread;
use super::*;
#[test]
fn test_mutex_usage() {
let mutex = Arc::new(Mutex::new(0));
assert_eq!(*mutex.lock().unwrap(), 0);
*mutex.lock().unwrap() = 1;
assert_eq!(*mutex.lock().unwrap(), 1);
let mutex_clone = mutex.clone();
let _guard = mutex.lock().unwrap();
let handle = thread::spawn(move || {
let result = mutex_clone.try_lock().unwrap_err();
assert!(matches!(result, TryLockError::WouldBlock));
});
handle.join().unwrap();
}
#[test]
fn test_rwlock_usage() {
let rwlock = Arc::new(RwLock::new(0));
assert_eq!(*rwlock.read().unwrap(), 0);
assert_eq!(*rwlock.write().unwrap(), 0);
*rwlock.write().unwrap() = 1;
assert_eq!(*rwlock.read().unwrap(), 1);
assert_eq!(*rwlock.write().unwrap(), 1);
let rwlock_clone = rwlock.clone();
let _read_lock = rwlock.read().unwrap();
let handle = thread::spawn(move || {
let write_result = rwlock_clone.try_write().unwrap_err();
assert!(matches!(write_result, TryLockError::WouldBlock));
let _read_lock = rwlock_clone.read().unwrap();
});
handle.join().unwrap();
}
#[test]
fn test_once_usage() {
let once = Arc::new(Once::new());
let once_clone = once.clone();
assert!(!once.is_completed());
let handle = thread::spawn(move || {
assert!(!once_clone.is_completed());
once_clone.call_once(|| {});
assert!(once_clone.is_completed());
});
handle.join().unwrap();
assert!(once.is_completed());
}
#[test]
#[should_panic(expected = "Found cycle in mutex dependency graph")]
fn test_detect_cycle() {
let a = Mutex::new(());
let b = Mutex::new(());
let hold_a = a.lock().unwrap();
let _ = b.lock();
drop(hold_a);
let _hold_b = b.lock().unwrap();
let _ = a.lock();
}
}