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    #[allow(clippy::missing_const_for_fn)]
20    pub fn new(nanos: u64) -> Self {
21        Self { nanos }
22    }
23
24    /// Create a new `Duration` from the given number of milliseconds.
25    ///
26    /// # Panics
27    /// if the number of milliseconds would overflow when converted to nanoseconds.
28    #[must_use]
29    pub fn from_millis(millis: u64) -> Self {
30        let nanos = millis
31            .checked_mul(u64::from(NANOS_PER_MILLI))
32            .expect("millis overflow");
33        Self { nanos }
34    }
35
36    /// Create a new `Duration` from the given number of seconds.
37    ///
38    /// # Panics
39    /// if the number of seconds would overflow when converted to nanoseconds.
40    #[must_use]
41    pub fn from_secs(seconds: u64) -> Self {
42        let nanos = seconds
43            .checked_mul(u64::from(NANOS_PER_SEC))
44            .expect("seconds overflow");
45        Self { nanos }
46    }
47}
48
49impl From<std::time::Duration> for Duration {
50    fn from(duration: std::time::Duration) -> Self {
51        Self {
52            // Safe because we don't expect durations to exceed u64::MAX nanoseconds in practice
53            #[allow(clippy::cast_possible_truncation)]
54            nanos: duration.as_nanos() as u64,
55        }
56    }
57}
58
59impl From<Duration> for std::time::Duration {
60    fn from(duration: Duration) -> Self {
61        Self::from_nanos(duration.nanos)
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use super::Duration;
68    use std::time::Duration as StdDuration;
69
70    #[test]
71    fn duration_from_millis() {
72        let duration = Duration::from_millis(1_000);
73        assert_eq!(duration.nanos, 1_000_000_000);
74    }
75
76    #[test]
77    fn duration_from_secs() {
78        let duration = Duration::from_secs(1);
79        assert_eq!(duration.nanos, 1_000_000_000);
80    }
81
82    #[test]
83    fn std_into_duration() {
84        let actual: Duration = StdDuration::from_millis(100).into();
85        let expected = Duration { nanos: 100_000_000 };
86        assert_eq!(actual, expected);
87    }
88
89    #[test]
90    fn duration_into_std() {
91        let actual: StdDuration = Duration { nanos: 100_000_000 }.into();
92        let expected = StdDuration::from_millis(100);
93        assert_eq!(actual, expected);
94    }
95}