use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use crate::Runtime;
use crate::TemporalReactor;
use crate::{EventId, EventNode};
pub async fn sleep<ReactorT: TemporalReactor>(rt: &Runtime<ReactorT>, duration: Duration) {
TimerFuture::new(rt, duration).await
}
enum TimerState {
Created { duration: Duration },
Scheduled,
Done,
}
struct TimerFuture<'runtime, ReactorT: TemporalReactor> {
rt: &'runtime Runtime<ReactorT>,
state: TimerState,
event_node: EventNode,
}
impl<'rt, ReactorT: TemporalReactor> TimerFuture<'rt, ReactorT> {
fn new(rt: &'rt Runtime<ReactorT>, duration: Duration) -> Self {
TimerFuture {
rt,
state: TimerState::Created { duration },
event_node: EventNode::new(),
}
}
fn schedule(&mut self, event_id: EventId, duration: Duration) -> Poll<()> {
debug_assert!(matches!(self.state, TimerState::Created { .. }));
self.state = TimerState::Scheduled;
self.rt.io().schedule_timer(event_id, duration);
Poll::Pending }
fn verify(&mut self) -> Poll<()> {
debug_assert!(matches!(self.state, TimerState::Scheduled));
if self.event_node.is_awoken_for(self.rt) {
self.state = TimerState::Done;
Poll::Ready(())
} else {
Poll::Pending
}
}
}
impl<'rt, ReactorT: TemporalReactor> Drop for TimerFuture<'rt, ReactorT> {
fn drop(&mut self) {
match self.state {
TimerState::Scheduled => {
self.event_node
.on_cancel()
.map(|event_id| self.rt.io().cancel_timer(event_id));
}
_ => (),
}
}
}
impl<'rt, ReactorT: TemporalReactor> Future for TimerFuture<'rt, ReactorT> {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
let this = unsafe { self.get_unchecked_mut() };
return match this.state {
TimerState::Created { duration } => {
let event_id = unsafe { this.event_node.on_pin(ctx) };
this.schedule(event_id, duration)
}
TimerState::Scheduled => this.verify(),
TimerState::Done => panic!("aiur/TimerFuture: was polled after completion."),
};
}
}