use core::{
cell::UnsafeCell,
sync::atomic::AtomicBool,
sync::atomic::Ordering::*,
future::poll_fn,
task::Poll,
ops::{Deref, DerefMut},
};
pub struct BusyMutex<T> {
value: UnsafeCell<T>,
locked: AtomicBool,
}
impl<T> From<T> for BusyMutex<T> {
fn from(value: T) -> Self {
Self {
value: value.into(),
locked: AtomicBool::new(false),
}
}
}
impl<T> BusyMutex<T> {
pub fn try_lock(&self) -> Option<BusyMutexGuard<'_, T>> {
BusyMutexGuard::try_new(self)
}
pub async fn lock(&self) -> BusyMutexGuard<'_, T> {
poll_fn(|_| match BusyMutexGuard::try_new(self) {
Some(guard) => Poll::Ready(guard),
None => Poll::Pending,
}).await
}
}
pub struct BusyMutexGuard<'m, T> {
mutex: &'m BusyMutex<T>,
}
impl<'m, T> BusyMutexGuard<'m, T> {
fn try_new(mutex: &'m BusyMutex<T>) -> Option<Self> {
if mutex.locked.swap(true, Acquire) == false
{Some(Self {mutex})}
else
{None}
}
}
impl<T> Deref for BusyMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe {& *self.mutex.value.get()}
}
}
impl<T> DerefMut for BusyMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe {&mut *self.mutex.value.get()}
}
}
impl<T> Drop for BusyMutexGuard<'_, T> {
fn drop(&mut self) {
self.mutex.locked.store(false, Release);
}
}