Skip to main content

duration_macro/
lib.rs

1//! [![crates.io](https://img.shields.io/crates/v/duration-macro.svg)](https://crates.io/crates/duration-macro)
2//! [![docs.rs](https://docs.rs/duration-macro/badge.svg)](https://docs.rs/duration-macro)
3//!
4//! Compile-time duration parsing.
5//!
6//! ```rust
7//! use core::time::Duration;
8//! use duration_macro::duration;
9//!
10//! assert_eq!(duration!(2 d 1 m), Duration::from_secs(3600 * 24 * 2 + 60 * 1));
11//! assert_eq!(duration!(1 m 2 d), Duration::from_secs(3600 * 24 * 2 + 60 * 1));
12//! assert_eq!(duration!(100 ns), Duration::from_nanos(100));
13//! assert_eq!(duration!({100 * 2} ns), Duration::from_nanos(200));
14//! ```
15//!
16//! For more details, please see the [duration!] docs.
17
18#![no_std]
19#![deny(missing_docs)]
20
21/// Compile-time duration parsing macro.
22///
23/// The macro accepts duration in a form of `{block} {unit} [{block} {unit}
24/// ...]`, where `{block}` is a ["token
25/// tree"](https://doc.rust-lang.org/reference/macros.html#macro-invocation),
26/// and `{unit}` is one of the following literals:
27/// * `d` or `day` or `days` for days,
28/// * `s` for seconds,
29/// * `ms` for milliseconds,
30/// * `us` for microseconds,
31/// * `ns` for nanoseconds.
32///
33/// ```rust
34/// use core::time::Duration;
35/// use duration_macro::duration;
36///
37/// let reference_duration = Duration::new(86400 + 3600 * 2 + 3 * 60 + 4, 5 * 1_000_000 + 6 * 1_000 + 7);
38/// assert_eq!(
39///     duration!(1 d 2 h 3 m 4 s 5 ms 6 us 7 ns),
40///     reference_duration
41/// );
42/// // The order doesn't matter!
43/// assert_eq!(
44///     duration!(6 us 2 h 3 m 4 s 1 d 5 ms 7 ns),
45///     reference_duration
46/// );
47/// // Expressions can be passed using `{..}` blocks:
48/// assert_eq!(
49///     duration!({3 * 2} ns {7 / 2} d),
50///     Duration::from_nanos(6) + Duration::from_secs(3 * 86400)
51/// );
52/// ```
53#[macro_export]
54macro_rules! duration {
55    ($something:tt $name:ident $($something2:tt $name2:ident)+) => {
56        $crate::duration!($something $name) $( + $crate::duration!($something2 $name2) )+
57    };
58    ($nanoseconds:tt ns) => {
59        ::core::time::Duration::from_nanos($nanoseconds)
60    };
61    ($milliseconds:tt ms) => {
62        ::core::time::Duration::from_millis($milliseconds)
63    };
64    ($microseconds:tt us) => {
65        ::core::time::Duration::from_micros($microseconds)
66    };
67    ($seconds:tt s) => {
68        ::core::time::Duration::from_secs($seconds)
69    };
70    ($minutes:tt m) => {
71        ::core::time::Duration::from_secs($minutes * 60)
72    };
73    ($hours:tt h) => {
74        ::core::time::Duration::from_secs($hours * 60 * 60)
75    };
76    ($days:tt d) => {
77        ::core::time::Duration::from_secs($days * 60 * 60 * 24)
78    };
79    ($days:tt day) => {
80        $crate::duration!($days d)
81    };
82    ($days:tt days) => {
83        $crate::duration!($days d)
84    };
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90    use core::time::Duration;
91
92    #[test]
93    fn it_works() {
94        assert_eq!(
95            duration!(1 d 2 h 3 m 4 s 5 ms 6 us 7 ns),
96            Duration::new(86400 + 3600 * 2 + 3 * 60 + 4, 5 * 1_000_000 + 6 * 1_000 + 7)
97        );
98    }
99
100    #[test]
101    fn days() {
102        assert_eq!(duration!(8 d), Duration::from_secs(8 * 86400));
103        assert_eq!(duration!(8 day), Duration::from_secs(8 * 86400));
104        assert_eq!(duration!(8 days), Duration::from_secs(8 * 86400));
105    }
106}