twizzler_abi/syscall/time/
units.rs1use 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 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 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 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 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 assert_eq!(Seconds(secs) * scalar, TimeSpan::new(secs * scalar, 0));
137
138 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 assert_eq!(
149 FemtoSeconds(femtos) * scalar,
150 TimeSpan::new(0, femtos * scalar)
151 );
152
153 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}