1use std::future::Future;
6use std::pin::Pin;
7use std::task::{Context, Poll};
8use std::time::Duration;
9
10use crate::Runtime;
11use crate::TemporalReactor;
12use crate::{EventId, EventNode};
13
14pub async fn sleep<ReactorT: TemporalReactor>(rt: &Runtime<ReactorT>, duration: Duration) {
21 TimerFuture::new(rt, duration).await
22}
23
24enum TimerState {
28 Created { duration: Duration },
29 Scheduled,
30 Done,
31}
32
33struct TimerFuture<'runtime, ReactorT: TemporalReactor> {
35 rt: &'runtime Runtime<ReactorT>,
36 state: TimerState,
37 event_node: EventNode,
38}
39
40impl<'rt, ReactorT: TemporalReactor> TimerFuture<'rt, ReactorT> {
41 fn new(rt: &'rt Runtime<ReactorT>, duration: Duration) -> Self {
42 TimerFuture {
43 rt,
44 state: TimerState::Created { duration },
45 event_node: EventNode::new(),
46 }
47 }
48
49 fn schedule(&mut self, event_id: EventId, duration: Duration) -> Poll<()> {
51 debug_assert!(matches!(self.state, TimerState::Created { .. }));
53
54 self.state = TimerState::Scheduled;
55 self.rt.io().schedule_timer(event_id, duration);
56 Poll::Pending }
58
59 fn verify(&mut self) -> Poll<()> {
61 debug_assert!(matches!(self.state, TimerState::Scheduled));
63
64 if self.event_node.is_awoken_for(self.rt) {
65 self.state = TimerState::Done;
66 Poll::Ready(())
67 } else {
68 Poll::Pending
69 }
70 }
71}
72
73impl<'rt, ReactorT: TemporalReactor> Drop for TimerFuture<'rt, ReactorT> {
75 fn drop(&mut self) {
76 match self.state {
77 TimerState::Scheduled => {
78 self.event_node
79 .on_cancel()
80 .map(|event_id| self.rt.io().cancel_timer(event_id));
81 }
82 _ => (),
83 }
84 }
85}
86
87impl<'rt, ReactorT: TemporalReactor> Future for TimerFuture<'rt, ReactorT> {
88 type Output = ();
89
90 fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
91 let this = unsafe { self.get_unchecked_mut() };
94
95 return match this.state {
96 TimerState::Created { duration } => {
97 let event_id = unsafe { this.event_node.on_pin(ctx) };
98 this.schedule(event_id, duration)
99 }
100 TimerState::Scheduled => this.verify(),
101 TimerState::Done => panic!("aiur/TimerFuture: was polled after completion."),
102 };
103 }
104}