Skip to main content

crux_time/protocol/
duration.rs

1use facet::Facet;
2use serde::{Deserialize, Serialize};
3
4/// The number of nanoseconds in seconds.
5const NANOS_PER_SEC: u32 = 1_000_000_000;
6/// The number of nanoseconds in a millisecond.
7const NANOS_PER_MILLI: u32 = 1_000_000;
8
9/// Represents a duration of time, internally stored as nanoseconds
10#[derive(Facet, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct Duration {
13    pub(crate) nanos: u64,
14}
15
16impl Duration {
17    /// Create a new `Duration` from the given number of nanoseconds.
18    #[must_use]
19    pub fn new(nanos: u64) -> Self {
20        Self { nanos }
21    }
22
23    /// Create a new `Duration` from the given number of milliseconds.
24    ///
25    /// # Panics
26    /// if the number of milliseconds would overflow when converted to nanoseconds.
27    #[must_use]
28    pub fn from_millis(millis: u64) -> Self {
29        let nanos = millis
30            .checked_mul(u64::from(NANOS_PER_MILLI))
31            .expect("millis overflow");
32        Self { nanos }
33    }
34
35    /// Create a new `Duration` from the given number of seconds.
36    ///
37    /// # Panics
38    /// if the number of seconds would overflow when converted to nanoseconds.
39    #[must_use]
40    pub fn from_secs(seconds: u64) -> Self {
41        let nanos = seconds
42            .checked_mul(u64::from(NANOS_PER_SEC))
43            .expect("seconds overflow");
44        Self { nanos }
45    }
46}
47
48impl From<std::time::Duration> for Duration {
49    fn from(duration: std::time::Duration) -> Self {
50        Duration {
51            // Safe because we don't expect durations to exceed u64::MAX nanoseconds in practice
52            #[allow(clippy::cast_possible_truncation)]
53            nanos: duration.as_nanos() as u64,
54        }
55    }
56}
57
58impl From<Duration> for std::time::Duration {
59    fn from(duration: Duration) -> Self {
60        std::time::Duration::from_nanos(duration.nanos)
61    }
62}
63
64#[cfg(test)]
65mod test {
66    use super::Duration;
67    use std::time::Duration as StdDuration;
68
69    #[test]
70    fn duration_from_millis() {
71        let duration = Duration::from_millis(1_000);
72        assert_eq!(duration.nanos, 1_000_000_000);
73    }
74
75    #[test]
76    fn duration_from_secs() {
77        let duration = Duration::from_secs(1);
78        assert_eq!(duration.nanos, 1_000_000_000);
79    }
80
81    #[test]
82    fn std_into_duration() {
83        let actual: Duration = StdDuration::from_millis(100).into();
84        let expected = Duration { nanos: 100_000_000 };
85        assert_eq!(actual, expected);
86    }
87
88    #[test]
89    fn duration_into_std() {
90        let actual: StdDuration = Duration { nanos: 100_000_000 }.into();
91        let expected = StdDuration::from_millis(100);
92        assert_eq!(actual, expected);
93    }
94}