tokio_util/time/mod.rs
1//! Additional utilities for tracking time.
2//!
3//! This module provides additional utilities for executing code after a set period
4//! of time. Currently there is only one:
5//!
6//! * `DelayQueue`: A queue where items are returned once the requested delay
7//! has expired.
8//!
9//! This type must be used from within the context of the `Runtime`.
10
11use std::future::Future;
12use std::time::Duration;
13use tokio::time::Timeout;
14
15mod wheel;
16
17pub mod delay_queue;
18
19#[doc(inline)]
20pub use delay_queue::DelayQueue;
21
22/// A trait which contains a variety of convenient adapters and utilities for `Future`s.
23pub trait FutureExt: Future {
24 /// A wrapper around [`tokio::time::timeout`], with the advantage that it is easier to write
25 /// fluent call chains.
26 ///
27 /// # Examples
28 ///
29 /// ```rust
30 /// use tokio::{sync::oneshot, time::Duration};
31 /// use tokio_util::time::FutureExt;
32 ///
33 /// # async fn dox() {
34 /// let (tx, rx) = oneshot::channel::<()>();
35 ///
36 /// let res = rx.timeout(Duration::from_millis(10)).await;
37 /// assert!(res.is_err());
38 /// # }
39 /// ```
40 fn timeout(self, timeout: Duration) -> Timeout<Self>
41 where
42 Self: Sized,
43 {
44 tokio::time::timeout(timeout, self)
45 }
46}
47
48impl<T: Future + ?Sized> FutureExt for T {}
49
50// ===== Internal utils =====
51
52enum Round {
53 Up,
54 Down,
55}
56
57/// Convert a `Duration` to milliseconds, rounding up and saturating at
58/// `u64::MAX`.
59///
60/// The saturating is fine because `u64::MAX` milliseconds are still many
61/// million years.
62#[inline]
63fn ms(duration: Duration, round: Round) -> u64 {
64 const NANOS_PER_MILLI: u32 = 1_000_000;
65 const MILLIS_PER_SEC: u64 = 1_000;
66
67 // Round up.
68 let millis = match round {
69 Round::Up => (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI,
70 Round::Down => duration.subsec_millis(),
71 };
72
73 duration
74 .as_secs()
75 .saturating_mul(MILLIS_PER_SEC)
76 .saturating_add(u64::from(millis))
77}