Skip to main content

compio_runtime/time/
future.rs

1use std::{
2    cell::RefCell,
3    pin::Pin,
4    rc::Rc,
5    task::{Context, Poll},
6    time::{Duration, Instant},
7};
8
9use crate::{
10    Runtime,
11    time::{TimerRuntime, runtime::TimerKey, sleep_until},
12};
13
14#[derive(Debug)]
15pub(crate) struct TimerFuture {
16    key: TimerKey,
17    rt: Rc<RefCell<TimerRuntime>>,
18}
19
20impl TimerFuture {
21    /// Try to create a new `TimerFuture` if the instant is in the future;
22    /// otherwise, a `None` will be returned.
23    ///
24    /// # Panics
25    ///
26    /// Panic if not running under a `Runtime`.
27    pub fn try_new(instant: Instant) -> Option<Self> {
28        Runtime::with_current(|rt| {
29            let key = rt.timer_runtime.borrow_mut().insert(instant)?;
30            Some(Self {
31                key,
32                rt: rt.timer_runtime.clone(),
33            })
34        })
35    }
36}
37
38impl Future for TimerFuture {
39    type Output = ();
40
41    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
42        self.rt.borrow_mut().poll_timer(cx, &self.key)
43    }
44}
45
46impl Drop for TimerFuture {
47    fn drop(&mut self) {
48        self.rt.borrow_mut().cancel(&self.key)
49    }
50}
51
52compio_driver::assert_not_impl!(TimerFuture, Send);
53compio_driver::assert_not_impl!(TimerFuture, Sync);
54
55/// Interval returned by [`interval`] and [`interval_at`]
56///
57/// This type allows you to wait on a sequence of instants with a certain
58/// duration between each instant. Unlike calling [`sleep`] in a loop, this lets
59/// you count the time spent between the calls to [`sleep`] as well.
60///
61/// [`sleep`]: super::sleep
62/// [`interval`]: super::interval
63/// [`interval_at`]: super::interval_at
64#[derive(Debug)]
65pub struct Interval {
66    first_ticked: bool,
67    start: Instant,
68    period: Duration,
69}
70
71impl Interval {
72    pub(crate) fn new(start: Instant, period: Duration) -> Self {
73        Self {
74            first_ticked: false,
75            start,
76            period,
77        }
78    }
79
80    /// Completes when the next instant in the interval has been reached.
81    ///
82    /// See [`interval`](super::interval) and
83    /// [`interval_at`](super::interval_at).
84    pub async fn tick(&mut self) -> Instant {
85        if !self.first_ticked {
86            sleep_until(self.start).await;
87            self.first_ticked = true;
88            self.start
89        } else {
90            let now = Instant::now();
91            let next = now + self.period
92                - Duration::from_nanos(
93                    ((now - self.start).as_nanos() % self.period.as_nanos()) as _,
94                );
95            sleep_until(next).await;
96            next
97        }
98    }
99}