use std::cell::UnsafeCell;
use std::marker::{PhantomData, PhantomPinned};
use std::pin::Pin;
use crate::wait_queue::{PinnedWaitQueue, WaitQueue};
#[derive(Debug, Default)]
pub struct Pager<'s, S: SyncResult> {
entry: UnsafeCell<Option<WaitQueue>>,
_phantom: PhantomData<&'s S>,
_pinned: PhantomPinned,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Error {
NotRegistered,
WrongMode,
NotReady,
}
pub trait SyncResult: Sized {
type Result: Clone + Copy + Eq + PartialEq;
fn to_result(value: u8, pager_error: Option<Error>) -> Self::Result;
}
impl<'s, S: SyncResult> Pager<'s, S> {
#[inline]
pub fn is_registered(&self) -> bool {
self.entry().is_some()
}
#[inline]
pub fn is_sync(&self) -> bool {
self.entry().is_some_and(|e| e.is_sync())
}
#[inline]
pub async fn poll_async(self: &mut Pin<&mut Pager<'s, S>>) -> S::Result {
let Some(entry) = self.entry() else {
return S::to_result(0, Some(Error::NotRegistered));
};
let pinned_entry = PinnedWaitQueue(entry);
let result = pinned_entry.await;
if result == WaitQueue::ERROR_WRONG_MODE {
return S::to_result(result, Some(Error::WrongMode));
}
self.with_entry_mut(|e| {
*e = None;
});
S::to_result(result, None)
}
#[inline]
pub fn poll_sync(self: &mut Pin<&mut Pager<'s, S>>) -> S::Result {
self.with_entry_mut(|e| {
let Some(entry) = e else {
return S::to_result(0, Some(Error::NotRegistered));
};
let result = entry.poll_result_sync();
if result == WaitQueue::ERROR_WRONG_MODE {
return S::to_result(0, Some(Error::WrongMode));
}
e.take();
S::to_result(result, None)
})
}
#[inline]
pub fn try_poll(&self) -> S::Result {
self.with_entry(|e| {
let Some(entry) = e else {
return S::to_result(0, Some(Error::NotRegistered));
};
if let Some(result) = entry.try_acknowledge_result() {
S::to_result(result, None)
} else {
S::to_result(0, Some(Error::NotReady))
}
})
}
#[inline]
pub(crate) fn entry(&self) -> Option<Pin<&WaitQueue>> {
unsafe { (*self.entry.get()).as_ref().map(|w| Pin::new_unchecked(w)) }
}
#[inline]
pub(crate) fn set_entry(&self, entry: WaitQueue) {
self.with_entry_mut(|e| e.replace(entry));
}
#[inline]
fn with_entry<R, F: FnOnce(&Option<WaitQueue>) -> R>(&self, f: F) -> R {
unsafe { f(&(*self.entry.get())) }
}
#[inline]
fn with_entry_mut<R, F: FnOnce(&mut Option<WaitQueue>) -> R>(&self, f: F) -> R {
unsafe { f(&mut (*self.entry.get())) }
}
}