kayrx_timer/lib.rs
1#![warn(
2 rust_2018_idioms,
3 unreachable_pub,
4 // missing_debug_implementations,
5 // missing_docs,
6)]
7#![allow(
8 warnings,
9 missing_docs,
10 type_alias_bounds,
11 clippy::type_complexity,
12 clippy::borrow_interior_mutable_const,
13 clippy::needless_doctest_main,
14 clippy::too_many_arguments,
15 clippy::new_without_default
16)]
17
18//! Time tracking
19//!
20//! This module provides a number of types for executing code after a set period
21//! of time.
22//!
23//! * `Delay` is a future that does no work and completes at a specific `Instant`
24//! in time.
25//!
26//! * `Interval` is a stream yielding a value at a fixed period. It is
27//! initialized with a `Duration` and repeatedly yields each time the duration
28//! elapses.
29//!
30//! * `Timeout`: Wraps a future or stream, setting an upper bound to the amount
31//! of time it is allowed to execute. If the future or stream does not
32//! complete in time, then it is canceled and an error is returned.
33//!
34//! * `DelayQueue`: A queue where items are returned once the requested delay
35//! has expired.
36//!
37//! These types are sufficient for handling a large number of scenarios
38//! involving time.
39//!
40//! These types must be used from within the context of the `Runtime`.
41//!
42//! # Examples
43//!
44//! Wait 100ms and print "Hello World!"
45//!
46//! ```
47//! use kayrx_timer::delay_for;
48//! use std::time::Duration;
49//! use kayrx_karx;
50//!
51//! fn main() {
52//! kayrx_karx::exec(async {
53//! delay_for(Duration::from_millis(100)).await;
54//! println!("100 ms have elapsed");
55//! });
56//! }
57//!
58//! ```
59//!
60//! Require that an operation takes no more than 300ms. Note that this uses the
61//! `timeout` function on the `FutureExt` trait. This trait is included in the
62//! prelude.
63//!
64//! ```
65//! use kayrx_timer::{timeout, Duration};
66//!
67//! async fn long_future() {
68//! // do work here
69//! }
70//!
71//! # async fn dox() {
72//! let res = timeout(Duration::from_secs(1), long_future()).await;
73//!
74//! if res.is_err() {
75//! println!("operation timed out");
76//! }
77//! # }
78//! ```
79
80pub mod delay_queue;
81
82pub use std::time::Duration;
83pub use clock::clock_util::{pause, resume};
84#[doc(inline)]
85pub use delay_queue::DelayQueue;
86pub use delay::{delay_for, delay_until, Delay};
87pub use error::Error;
88pub use self::instant::Instant;
89pub use interval::{interval, interval_at, Interval};
90#[doc(inline)]
91pub use timeout::{timeout, timeout_at, Elapsed, Timeout};
92pub use throttle::{throttle, Throttle};
93
94mod clock;
95mod error;
96mod delay;
97mod instant;
98mod interval;
99mod throttle;
100mod timeout;
101mod wheel;
102
103pub(crate) use self::clock::Clock;
104pub(crate) mod driver;
105
106// ===== Internal utils =====
107
108enum Round {
109 Up,
110 Down,
111}
112
113/// Convert a `Duration` to milliseconds, rounding up and saturating at
114/// `u64::MAX`.
115///
116/// The saturating is fine because `u64::MAX` milliseconds are still many
117/// million years.
118#[inline]
119fn ms(duration: Duration, round: Round) -> u64 {
120 const NANOS_PER_MILLI: u32 = 1_000_000;
121 const MILLIS_PER_SEC: u64 = 1_000;
122
123 // Round up.
124 let millis = match round {
125 Round::Up => (duration.subsec_nanos() + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI,
126 Round::Down => duration.subsec_millis(),
127 };
128
129 duration
130 .as_secs()
131 .saturating_mul(MILLIS_PER_SEC)
132 .saturating_add(u64::from(millis))
133}