use core::cell::UnsafeCell;
use core::future::Future;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::task::{Context, Poll};
use core::time::Duration;
use alloc::sync::Arc;
use crate::os::Semaphore;
use crate::traits::SemaphoreFn;
use crate::utils::OsalRsBool;
use super::waker_slot::WakerSlot;
pub struct AsyncMutex<T> {
sem: Arc<Semaphore>,
waker: Arc<WakerSlot>,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for AsyncMutex<T> {}
unsafe impl<T: Send> Sync for AsyncMutex<T> {}
impl<T> AsyncMutex<T> {
pub fn new(value: T) -> Self {
let sem = Semaphore::new(1, 1)
.expect("AsyncMutex: failed to create binary semaphore");
Self {
sem: Arc::new(sem),
waker: Arc::new(WakerSlot::new()),
data: UnsafeCell::new(value),
}
}
pub fn lock(&self) -> LockFuture<'_, T> {
LockFuture { mutex: self }
}
}
pub struct AsyncMutexGuard<'a, T> {
mutex: &'a AsyncMutex<T>,
}
impl<'a, T> Deref for AsyncMutexGuard<'a, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.data.get() }
}
}
impl<'a, T> DerefMut for AsyncMutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<'a, T> Drop for AsyncMutexGuard<'a, T> {
fn drop(&mut self) {
self.mutex.sem.signal();
self.mutex.waker.wake();
}
}
pub struct LockFuture<'a, T> {
mutex: &'a AsyncMutex<T>,
}
impl<'a, T> Future for LockFuture<'a, T> {
type Output = AsyncMutexGuard<'a, T>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.mutex.sem.wait(Duration::ZERO) == OsalRsBool::True {
return Poll::Ready(AsyncMutexGuard { mutex: self.mutex });
}
self.mutex.waker.store(cx.waker());
if self.mutex.sem.wait(Duration::ZERO) == OsalRsBool::True {
Poll::Ready(AsyncMutexGuard { mutex: self.mutex })
} else {
Poll::Pending
}
}
}