use crate::{Puck, config::Config, continuation::Continuation, ptr::Irc, simulator::Sim};
use core::{
future::{Future, poll_fn},
pin::Pin,
task::{Context, Poll},
};
pub fn sim<C: Config>() -> impl Future<Output = Option<Irc<Sim<C>>>> {
poll_fn(|cx| Poll::Ready(Sim::from_context(cx)))
}
pub fn sleep() -> impl Future<Output = ()> {
let mut ready = false;
poll_fn(move |_cx| {
if ready {
Poll::Ready(())
} else {
ready = true;
Poll::Pending
}
})
}
pub fn defer() -> impl Future<Output = ()> {
let mut ready = false;
poll_fn(move |cx| {
if ready {
Poll::Ready(())
} else {
ready = true;
cx.waker().wake_by_ref();
Poll::Pending
}
})
}
pub fn waker() -> impl Future<Output = core::task::Waker> {
poll_fn(|cx| Poll::Ready(cx.waker().clone()))
}
#[inline]
pub const fn join<C, P>(puck: P) -> Join<C, P>
where
C: ?Sized + Config,
P: Puck<C> + AsRef<Continuation<'static, C>> + Unpin,
{
Join {
publisher: puck,
subscriber: None,
}
}
pub struct Join<C: ?Sized + Config, P: Puck<C> + AsRef<Continuation<'static, C>>> {
publisher: P,
subscriber: Option<Irc<Continuation<'static, C>>>,
}
impl<C, P> Drop for Join<C, P>
where
C: ?Sized + Config,
P: Puck<C> + AsRef<Continuation<'static, C>>,
{
fn drop(&mut self) {
if let Some(active) = self.subscriber.take() {
unsafe {
self.publisher.as_ref().remove_pending(&active);
}
}
}
}
impl<C, P> Future for Join<C, P>
where
C: ?Sized + Config,
P: Puck<C> + AsRef<Continuation<'static, C>>,
{
type Output = P::Output;
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
self.subscriber = None;
match self.publisher.result() {
Some(result) => Poll::Ready(result),
None => {
let active = self.publisher.sim().active().into_inner();
self.subscriber = Some(active.clone());
self.publisher.as_ref().insert_pending(active);
Poll::Pending
}
}
}
}