twizzler_abi/syscall/time/
units.rs

1use core::ops::Mul;
2
3use super::TimeSpan;
4
5pub const FEMTOS_PER_SEC: u64 = 1_000_000_000_000_000;
6pub const FEMTOS_PER_NANO: u64 = 1_000_000;
7pub const NANOS_PER_SEC: u64 = 1_000_000_000;
8
9#[derive(Debug)]
10pub enum TimeUnitError {
11    ConversionOverflow,
12}
13
14#[derive(Clone, Copy, Debug, PartialEq, Default)]
15#[repr(transparent)]
16pub struct Seconds(pub u64);
17
18impl Mul<Seconds> for u64 {
19    type Output = TimeSpan;
20
21    fn mul(self, rhs: Seconds) -> Self::Output {
22        TimeSpan::from_secs(self * rhs.0)
23    }
24}
25
26impl Mul<u64> for Seconds {
27    type Output = TimeSpan;
28
29    // apply reflexive property
30    fn mul(self, rhs: u64) -> Self::Output {
31        rhs * self
32    }
33}
34
35#[derive(Clone, Copy, Debug, PartialEq)]
36#[repr(transparent)]
37pub struct MilliSeconds(pub u64);
38
39#[derive(Clone, Copy, Debug, PartialEq)]
40#[repr(transparent)]
41pub struct MicroSeconds(pub u64);
42
43#[derive(Clone, Copy, Debug, PartialEq)]
44#[repr(transparent)]
45pub struct NanoSeconds(pub u64);
46
47#[derive(Clone, Copy, Debug, PartialEq)]
48#[repr(transparent)]
49pub struct PicoSeconds(pub u64);
50
51#[derive(Clone, Copy, Debug, PartialEq, Default)]
52#[repr(transparent)]
53pub struct FemtoSeconds(pub u64);
54
55impl Mul<FemtoSeconds> for u64 {
56    type Output = TimeSpan;
57
58    fn mul(self, rhs: FemtoSeconds) -> Self::Output {
59        let t = self as u128 * rhs.0 as u128;
60        TimeSpan::new(
61            (t / FEMTOS_PER_SEC as u128) as u64,
62            (t % FEMTOS_PER_SEC as u128) as u64,
63        )
64    }
65}
66
67impl Mul<u64> for FemtoSeconds {
68    type Output = TimeSpan;
69
70    // apply reflexive property
71    fn mul(self, rhs: u64) -> Self::Output {
72        rhs * self
73    }
74}
75
76macro_rules! impl_scalar_mul {
77    ($unit: ident, $conver: expr) => {
78        impl Mul<$unit> for u64 {
79            type Output = TimeSpan;
80
81            fn mul(self, rhs: $unit) -> Self::Output {
82                let t = self as u128 * rhs.0 as u128;
83                let f: FemtoSeconds = $unit((t % $conver as u128) as u64).try_into().unwrap();
84                TimeSpan::new((t / $conver as u128) as u64, f.0)
85            }
86        }
87
88        impl Mul<u64> for $unit {
89            type Output = TimeSpan;
90
91            // apply reflexive property
92            fn mul(self, rhs: u64) -> Self::Output {
93                rhs * self
94            }
95        }
96    };
97}
98
99impl_scalar_mul!(NanoSeconds, NANOS_PER_SEC);
100
101macro_rules! impl_unit_conversion {
102    ($big: ident, $small: ident, $conver: expr) => {
103        impl From<$small> for $big {
104            fn from(unit: $small) -> Self {
105                $big(unit.0 / $conver)
106            }
107        }
108
109        // conversion to a smaller unit might fail (overlfow)
110        impl TryFrom<$big> for $small {
111            type Error = TimeUnitError;
112            fn try_from(unit: $big) -> Result<Self, Self::Error> {
113                match unit.0.checked_mul($conver) {
114                    Some(t) => Ok($small(t)),
115                    None => Err(TimeUnitError::ConversionOverflow),
116                }
117            }
118        }
119    };
120}
121
122impl_unit_conversion!(Seconds, FemtoSeconds, FEMTOS_PER_SEC);
123impl_unit_conversion!(NanoSeconds, FemtoSeconds, FEMTOS_PER_NANO);
124
125#[cfg(test)]
126mod tests {
127
128    use crate::syscall::{FemtoSeconds, Seconds, TimeSpan, FEMTOS_PER_SEC};
129
130    #[test]
131    fn secs_mult() {
132        let scalar: u64 = 100;
133        let secs: u64 = 5;
134
135        // lhs is Seconds(), rhs is a scalar
136        assert_eq!(Seconds(secs) * scalar, TimeSpan::new(secs * scalar, 0));
137
138        // lhs is a scalar, rhs is Seconds()
139        assert_eq!(scalar * Seconds(secs), TimeSpan::new(secs * scalar, 0));
140    }
141
142    #[test]
143    fn femtos_mult() {
144        let scalar: u64 = 1234;
145        let femtos: u64 = 500;
146
147        // lhs is FemtoSeconds(), rhs is a scalar
148        assert_eq!(
149            FemtoSeconds(femtos) * scalar,
150            TimeSpan::new(0, femtos * scalar)
151        );
152
153        // lhs is a scalar, rhs is FemtoSeconds()
154        assert_eq!(
155            scalar * FemtoSeconds(femtos),
156            TimeSpan::new(0, femtos * scalar)
157        );
158    }
159
160    #[test]
161    fn conversion() {
162        let femtos = FemtoSeconds(FEMTOS_PER_SEC * 3);
163        let mut secs: Seconds = femtos.into();
164
165        assert_eq!(secs, Seconds(3));
166
167        secs = Seconds(3);
168        let f: FemtoSeconds = secs
169            .try_into()
170            .expect("could not convert Seconds to FemtoSeconds");
171
172        assert_eq!(femtos, f);
173    }
174}