#![forbid(unsafe_code)]
use core::future::Future;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::task::{Context, Poll};
use std::collections::VecDeque;
use std::sync::TryLockError;
use std::task::Waker;
#[allow(clippy::module_name_repetitions)]
pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>,
value_guard: Option<std::sync::MutexGuard<'a, T>>,
}
impl<'a, T> MutexGuard<'a, T> {
fn new(mutex: &'a Mutex<T>, value_guard: std::sync::MutexGuard<'a, T>) -> MutexGuard<'a, T> {
let mut inner_guard = mutex.inner.lock().unwrap();
assert!(!inner_guard.locked);
inner_guard.locked = true;
MutexGuard {
mutex,
value_guard: Some(value_guard),
}
}
}
impl<'a, T> Drop for MutexGuard<'a, T> {
fn drop(&mut self) {
let mut wakers = VecDeque::new();
{
let mut inner_guard = self.mutex.inner.lock().unwrap();
assert!(inner_guard.locked);
inner_guard.locked = false;
std::mem::swap(&mut inner_guard.wakers, &mut wakers);
}
self.value_guard.take();
for waker in wakers {
waker.wake();
}
}
}
impl<'a, T> Deref for MutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&*self.value_guard.as_ref().unwrap()
}
}
impl<'a, T> DerefMut for MutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.value_guard.as_mut().unwrap()
}
}
#[doc(hidden)]
pub struct LockFuture<'a, T> {
mutex: &'a Mutex<T>,
}
impl<'a, T> Future for LockFuture<'a, T> {
type Output = MutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
loop {
match self.mutex.value.try_lock() {
Ok(guard) => return Poll::Ready(MutexGuard::new(self.mutex, guard)),
Err(TryLockError::Poisoned(e)) => panic!("{}", e),
Err(TryLockError::WouldBlock) => {}
}
let mut guard = self.mutex.inner.lock().unwrap();
if guard.locked {
guard.wakers.push_back(cx.waker().clone());
return Poll::Pending;
}
}
}
}
struct Inner {
wakers: VecDeque<Waker>,
locked: bool,
}
pub struct Mutex<T> {
inner: std::sync::Mutex<Inner>,
value: std::sync::Mutex<T>,
}
impl<T> Mutex<T> {
pub fn new(value: T) -> Mutex<T> {
Self {
inner: std::sync::Mutex::new(Inner {
wakers: VecDeque::new(),
locked: false,
}),
value: std::sync::Mutex::new(value),
}
}
pub async fn lock(&self) -> MutexGuard<'_, T> {
LockFuture { mutex: self }.await
}
}