crux_time/protocol/
duration.rs

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