use super::wait_queue::WaitQueue;
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::task::{Context, Poll};
#[repr(align(64))]
pub struct Notify {
permit: AtomicBool,
wait: WaitQueue,
}
impl Default for Notify {
fn default() -> Self {
Self::new()
}
}
impl Notify {
#[must_use]
pub const fn new() -> Self {
Self {
permit: AtomicBool::new(false),
wait: WaitQueue::new(),
}
}
#[inline(always)]
pub fn notify_one(&self) {
self.permit.store(true, Ordering::Release);
self.wait.wake_one();
}
#[inline(always)]
pub fn notify_waiters(&self) {
self.wait.wake_all();
}
pub const fn notified(&self) -> Notified<'_> {
Notified { notify: self }
}
}
#[repr(align(64))]
pub struct Notified<'a> {
notify: &'a Notify,
}
impl Future for Notified<'_> {
type Output = ();
#[inline(always)]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> {
if self
.notify
.permit
.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
return Poll::Ready(());
}
let token = self.notify.wait.register(cx.waker());
if self
.notify
.permit
.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
self.notify.wait.cancel(token);
return Poll::Ready(());
}
Poll::Pending
}
}