epoch_cli/
conversions.rs

1//! This module contains methods for converting between time bases.
2//!
3//! Conversions are performed with the `checked_*` family of methods that will throw an error on
4//! underflow or overflow instead of panicking or silent data corruption.
5
6use crate::errors::Result;
7use crate::EpochError;
8
9/// nanoseconds per millisecond
10pub const NS_PER_MS_U32: u32 = 1_000_000;
11
12/// nanoseconds per microsecond
13pub const NS_PER_US_U32: u32 = 1_000;
14
15/// nanoseconds per millisecond
16pub const NS_PER_MS_I128: i128 = 1_000_000;
17
18/// nanoseconds per microsecond
19pub const NS_PER_US_I128: i128 = 1_000;
20
21/// Converts milliseconds to nanoseconds. Returns an error on underflow or overflow.
22pub fn ms_to_ns_u32(ms: u32) -> Result<u32> {
23    ms.checked_mul(NS_PER_MS_U32).ok_or_else(|| {
24        EpochError::numeric_precision(format!("Conversion from {}ms to ns (u32)", ms).as_str())
25    })
26}
27
28/// Converts microseconds to nanoseconds. Returns an error on underflow or overflow.
29pub fn us_to_ns_u32(us: u32) -> Result<u32> {
30    us.checked_mul(NS_PER_US_U32).ok_or_else(|| {
31        EpochError::numeric_precision(format!("Conversion from {}us to ns (u32)", us).as_str())
32    })
33}
34
35/// Converts milliseconds to nanoseconds. Returns an error on underflow or overflow.
36pub fn ms_to_ns_i128(ms: i128) -> Result<i128> {
37    ms.checked_mul(NS_PER_MS_I128).ok_or_else(|| {
38        EpochError::numeric_precision(format!("Conversion from {}ms to ns (i128)", ms).as_str())
39    })
40}
41
42/// Converts microseconds to nanoseconds. Returns an error on underflow or overflow.
43pub fn us_to_ns_i128(us: i128) -> Result<i128> {
44    us.checked_mul(NS_PER_US_I128).ok_or_else(|| {
45        EpochError::numeric_precision(format!("Conversion from {}us to ns (i128)", us).as_str())
46    })
47}
48
49/// Converts nanoseconds to milliseconds. Returns an error on underflow or overflow.
50pub fn ns_to_ms_i128(ns: i128) -> Result<i128> {
51    ns.checked_div(NS_PER_MS_I128).ok_or_else(|| {
52        EpochError::numeric_precision(format!("Conversion from {}ns to ms (i128)", ns).as_str())
53    })
54}
55
56/// Converts nanoseconds to microseconds. Returns an error on underflow or overflow.
57pub fn ns_to_us_i128(ns: i128) -> Result<i128> {
58    ns.checked_div(NS_PER_US_I128).ok_or_else(|| {
59        EpochError::numeric_precision(format!("Conversion from {}ns to us (i128)", ns).as_str())
60    })
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_ms_to_ns_u32_zero() {
69        assert_eq!(ms_to_ns_u32(0).unwrap(), 0)
70    }
71
72    #[test]
73    fn test_ms_to_ns_u32_one() {
74        assert_eq!(ms_to_ns_u32(1).unwrap(), 1_000_000)
75    }
76
77    #[test]
78    fn test_ms_to_ns_u32_bad() {
79        assert!(ms_to_ns_u32(u32::MAX).is_err());
80    }
81
82    #[test]
83    fn test_ms_to_ns_i128_zero() {
84        assert_eq!(ms_to_ns_i128(0).unwrap(), 0)
85    }
86
87    #[test]
88    fn test_ms_to_ns_i128_one() {
89        assert_eq!(ms_to_ns_i128(1).unwrap(), 1_000_000)
90    }
91
92    #[test]
93    fn test_ms_to_ns_i128_minus_one() {
94        assert_eq!(ms_to_ns_i128(-1).unwrap(), -1_000_000)
95    }
96
97    #[test]
98    fn test_us_to_ns_u32_zero() {
99        assert_eq!(us_to_ns_u32(0).unwrap(), 0)
100    }
101
102    #[test]
103    fn test_us_to_ns_u32_one() {
104        assert_eq!(us_to_ns_u32(1).unwrap(), 1_000)
105    }
106
107    #[test]
108    fn test_us_to_ns_i128_zero() {
109        assert_eq!(us_to_ns_i128(0).unwrap(), 0)
110    }
111
112    #[test]
113    fn test_us_to_ns_i128_one() {
114        assert_eq!(us_to_ns_i128(1).unwrap(), 1_000)
115    }
116
117    #[test]
118    fn test_us_to_ns_i128_minus_one() {
119        assert_eq!(us_to_ns_i128(-1).unwrap(), -1_000)
120    }
121}