use std::{
cell::RefCell,
future::Future,
pin::Pin,
rc::Rc,
task::{Context, Poll, Waker},
};
#[derive(Debug, Default)]
struct OnceEventState {
wakers: RefCell<Option<Vec<Waker>>>,
}
impl OnceEventState {
fn new() -> Self {
Self {
wakers: RefCell::new(Some(Vec::new())),
}
}
}
#[derive(Debug, Clone, Default)]
pub struct OnceEvent {
state: Rc<OnceEventState>,
}
impl OnceEvent {
pub fn new() -> Self {
let initial_state = OnceEventState::new();
Self {
state: Rc::new(initial_state),
}
}
pub fn notify(&self) {
if let Some(wakers) = { self.state.wakers.borrow_mut().take() } {
for waker in wakers {
waker.wake();
}
}
}
pub fn listen(&self) -> OnceListener {
OnceListener {
state: self.state.clone(),
}
}
}
#[derive(Debug)]
pub struct OnceListener {
state: Rc<OnceEventState>,
}
impl Future for OnceListener {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut wakers_guard = self.state.wakers.borrow_mut();
match &mut *wakers_guard {
Some(wakers) => {
if !wakers.iter().any(|w| w.will_wake(cx.waker())) {
wakers.push(cx.waker().clone());
}
Poll::Pending
}
None => {
Poll::Ready(())
}
}
}
}
impl Unpin for OnceListener {}