diff --git a/tokio/src/time/interval.rs b/tokio/src/time/interval.rs index 2e153fdbe7a..feccce26924 100644 --- a/tokio/src/time/interval.rs +++ b/tokio/src/time/interval.rs @@ -140,6 +140,7 @@ fn internal_interval_at( Interval { delay, period, + prev_period: None, missed_tick_behavior: Default::default(), #[cfg(all(tokio_unstable, feature = "tracing"))] resource_span, @@ -399,6 +400,10 @@ pub struct Interval { /// The strategy `Interval` should use when a tick is missed. missed_tick_behavior: MissedTickBehavior, + /// The previous period is used to restore the period after + /// using `reset_immediately`, `reset_after` or `reset_at`. + prev_period: Option, + #[cfg(all(tokio_unstable, feature = "tracing"))] resource_span: tracing::Span, } @@ -444,7 +449,15 @@ impl Interval { #[cfg(not(all(tokio_unstable, feature = "tracing")))] let instant = poll_fn(|cx| self.poll_tick(cx)); - instant.await + let instant = instant.await; + + if let Some(period) = self.prev_period { + self.period = period; + self.prev_period = None; + self.reset(); + } + + instant } /// Polls for the next instant in the interval to be reached. @@ -521,6 +534,105 @@ impl Interval { self.delay.as_mut().reset(Instant::now() + self.period); } + /// Resets the interval immediately. + /// + /// This method ignores [`MissedTickBehavior`] strategy. + /// + /// # Examples + /// + /// ``` + /// use tokio::time; + /// + /// use std::time::Duration; + /// + /// #[tokio::main] + /// async fn main() { + /// let mut interval = time::interval(Duration::from_millis(100)); + /// + /// interval.tick().await; + /// + /// time::sleep(Duration::from_millis(50)).await; + /// interval.reset_immediately(); + /// + /// interval.tick().await; + /// interval.tick().await; + /// + /// // approximately 150ms have elapsed. + /// } + /// ``` + pub fn reset_immediately(&mut self) { + self.prev_period = Some(self.period); + + self.delay.as_mut().reset(Instant::now()); + } + + /// Resets the interval after the specified [`std::time::Duration`]. + /// + /// This method ignores [`MissedTickBehavior`] strategy. + /// + /// # Examples + /// + /// ``` + /// use tokio::time; + /// + /// use std::time::Duration; + /// + /// #[tokio::main] + /// async fn main() { + /// let mut interval = time::interval(Duration::from_millis(100)); + /// interval.tick().await; + /// + /// time::sleep(Duration::from_millis(50)).await; + /// + /// let after = Duration::from_millis(20); + /// interval.reset_after(after); + /// + /// interval.tick().await; + /// interval.tick().await; + /// + /// // approximately 170ms have elapsed. + /// } + /// ``` + pub fn reset_after(&mut self, after: Duration) { + self.prev_period = Some(self.period); + + self.delay.as_mut().reset(Instant::now() + after); + } + + /// Resets the interval to a [`crate::time::instant::Instant`] deadline. + /// If deadline is in the past it behaves like `reset_immediately`. + /// + /// This method ignores [`MissedTickBehavior`] strategy. + /// + /// # Examples + /// + /// ``` + /// use tokio::time::{self, Instant}; + /// + /// use std::time::Duration; + /// + /// #[tokio::main] + /// async fn main() { + /// let mut interval = time::interval(Duration::from_millis(100)); + /// interval.tick().await; + /// + /// time::sleep(Duration::from_millis(50)).await; + /// + /// let deadline = Instant::now() + Duration::from_millis(30); + /// interval.reset_at(deadline); + /// + /// interval.tick().await; + /// interval.tick().await; + /// + /// // approximately 180ms have elapsed. + /// } + /// ``` + pub fn reset_at(&mut self, deadline: Instant) { + self.prev_period = Some(self.period); + + self.delay.as_mut().reset(deadline); + } + /// Returns the [`MissedTickBehavior`] strategy currently being used. pub fn missed_tick_behavior(&self) -> MissedTickBehavior { self.missed_tick_behavior