use crate::guard::Guard;
use crate::spinlock::Spinlock;
use std::cell::UnsafeCell;
use std::sync::atomic::AtomicBool;
#[cfg(not(target_arch = "wasm32"))]
use std::thread;
#[cfg(target_arch = "wasm32")]
use wasm_safe_thread as thread;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
#[cfg(target_arch = "wasm32")]
use web_time::Instant;
mod async_impl;
mod block;
mod not_available;
mod spin;
mod sync_impl;
mod with;
pub use not_available::NotAvailable;
#[derive(Debug)]
pub struct Mutex<T> {
pub(crate) inner: UnsafeCell<T>,
pub(crate) data_lock: AtomicBool,
pub(crate) waiting_sync_threads: Spinlock<Vec<thread::Thread>>,
pub(crate) waiting_async_threads: Spinlock<Vec<r#continue::Sender<()>>>,
}
impl<T> Mutex<T> {
pub const fn new(value: T) -> Self {
Mutex {
inner: UnsafeCell::new(value),
data_lock: AtomicBool::new(false),
waiting_sync_threads: Spinlock::new(vec![]),
waiting_async_threads: Spinlock::new(vec![]),
}
}
pub fn try_lock(&self) -> Result<Guard<'_, T>, NotAvailable> {
if self
.data_lock
.compare_exchange(
false,
true,
std::sync::atomic::Ordering::Acquire,
std::sync::atomic::Ordering::Relaxed,
)
.is_ok()
{
let data = unsafe { &mut *self.inner.get() };
Ok(Guard { mutex: self, data })
} else {
Err(NotAvailable)
}
}
pub fn lock_spin(&self) -> Guard<'_, T> {
spin::lock_spin(self)
}
pub fn lock_spin_timeout(&self, deadline: Instant) -> Option<Guard<'_, T>> {
spin::lock_spin_timeout(self, deadline)
}
pub fn lock_block(&self) -> Guard<'_, T> {
block::lock_block(self)
}
pub fn lock_block_timeout(&self, deadline: Instant) -> Option<Guard<'_, T>> {
block::lock_block_timeout(self, deadline)
}
pub async fn lock_async(&self) -> Guard<'_, T> {
async_impl::lock_async(self).await
}
pub async fn lock_async_timeout(&self, deadline: Instant) -> Option<Guard<'_, T>> {
async_impl::lock_async_timeout(self, deadline).await
}
pub(crate) fn did_unlock(&self) {
let threads = self.waiting_sync_threads.with_mut(std::mem::take);
for thread in threads {
thread.unpark();
}
let senders = self.waiting_async_threads.with_mut(std::mem::take);
for sender in senders {
sender.send(());
}
}
pub fn lock_sync(&self) -> Guard<'_, T> {
sync_impl::lock_sync(self)
}
pub fn lock_sync_timeout(&self, deadline: Instant) -> Option<Guard<'_, T>> {
sync_impl::lock_sync_timeout(self, deadline)
}
pub fn with_sync<R, F: FnOnce(&T) -> R>(&self, f: F) -> R {
with::with_sync(self, f)
}
pub fn with_mut_sync<R, F: FnOnce(&mut T) -> R>(&self, f: F) -> R {
with::with_mut_sync(self, f)
}
pub async fn with_async<R, F: FnOnce(&T) -> R>(&self, f: F) -> R {
with::with_async(self, f).await
}
pub async fn with_mut_async<R, F: FnOnce(&mut T) -> R>(&self, f: F) -> R {
with::with_mut_async(self, f).await
}
}
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Send> Sync for Mutex<T> {}
impl<T: Default> Default for Mutex<T> {
fn default() -> Self {
Mutex::new(T::default())
}
}
impl<T: std::fmt::Display> std::fmt::Display for Mutex<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.try_lock() {
Ok(guard) => std::fmt::Display::fmt(&*guard, f),
Err(_) => write!(f, "Mutex {{ <locked> }}"),
}
}
}
impl<T> From<T> for Mutex<T> {
fn from(value: T) -> Self {
Mutex::new(value)
}
}