//!Interval module #[cfg(not(target_arch = "wasm32"))] use std::time; #[cfg(target_arch = "wasm32")] use web_time as time; use core::task; use core::future::Future; use core::pin::Pin; use crate::timer::Timer; use crate::timer::Platform as PlatformTimer; ///Periodic Timer /// ///On each completion, underlying timer is restarted and therefore `Future` can be polled once ///more. /// ///## Usage /// ///```rust, no_run ///async fn job() { ///} /// ///async fn do_a_while() { /// let mut times: u8 = 0; /// let mut interval = async_timer::Interval::platform_new(core::time::Duration::from_secs(1)); /// /// while times < 5 { /// job().await; /// interval.wait().await; /// times += 1; /// } ///} ///``` #[must_use = "Interval does nothing unless polled"] pub struct Interval { timer: T, ///Timer interval, change to this value will be reflected on next restart of timer. pub interval: time::Duration, finish_at: time::Instant, } impl Interval { #[inline(always)] ///Creates new instance using platform timer pub fn platform_new(interval: time::Duration) -> Self { Interval::::new(interval) } } impl Interval { ///Creates new instance with specified timer type. pub fn new(interval: time::Duration) -> Self { Self { timer: T::new(interval), finish_at: time::Instant::now() + interval, interval, } } #[inline(always)] ///Stops interval pub fn cancel(&mut self) { self.timer.cancel() } ///Restarts interval pub fn restart(&mut self) { let now = time::Instant::now(); let interval = match now.checked_duration_since(self.finish_at) { Some(delayed) => self.interval - time::Duration::from_nanos((delayed.as_nanos() % self.interval.as_nanos()) as _), None => self.interval }; self.timer.restart(interval); } #[inline(always)] ///Returns future for next expiration. pub fn wait<'a>(&'a mut self) -> impl Future + 'a { self } } impl Future for &'_ mut Interval { type Output = (); fn poll(mut self: Pin<&mut Self>, ctx: &mut task::Context) -> task::Poll { match Future::poll(Pin::new(&mut self.timer), ctx) { task::Poll::Ready(()) => { self.restart(); task::Poll::Ready(()) }, task::Poll::Pending => task::Poll::Pending, } } }