asim/
time.rs

1use serde::{Deserialize, Serialize};
2
3/// The time at which the simulation started
4pub const START_TIME: Time = Time(0);
5
6/// Elapsed time in nanoseconds
7#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
8pub struct Time(u64);
9
10#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
11pub struct Duration(u64);
12
13impl Time {
14    pub const fn from_micros(micros: u64) -> Self {
15        Self(micros)
16    }
17
18    pub const fn from_millis(millis: u64) -> Self {
19        Self::from_micros(millis * 1000)
20    }
21
22    pub const fn from_seconds(seconds: u64) -> Self {
23        Self::from_millis((seconds as u64) * 1000)
24    }
25
26    pub const fn from_minutes(minutes: u64) -> Self {
27        Self::from_seconds(minutes * 60)
28    }
29
30    pub const fn from_hours(hours: u64) -> Self {
31        Self::from_minutes(60 * hours)
32    }
33
34    /// Get elapsed hours (rounded down)
35    pub fn to_hours(&self) -> u64 {
36        self.to_seconds() / (60 * 60)
37    }
38
39    /// Get elapsed minutes (rounded down)
40    pub fn to_minutes(self) -> u64 {
41        self.to_seconds() / 60
42    }
43
44    /// Get elapsed seconds (rounded down)
45    pub fn to_seconds(&self) -> u64 {
46        (self.0 / (1_000_000)) as u64
47    }
48
49    pub fn to_millis(&self) -> u64 {
50        (self.0 / 1_000) as u64
51    }
52
53    pub fn as_micros(&self) -> u64 {
54        self.0
55    }
56
57    pub fn as_millis_f64(&self) -> f64 {
58        (self.0 as f64) / 1_000.0
59    }
60
61    pub fn as_seconds_f64(&self) -> f64 {
62        (self.0 as f64) / (1_000_000.0)
63    }
64}
65
66impl Duration {
67    pub const fn from_micros(micros: u64) -> Self {
68        Self(micros)
69    }
70
71    pub const fn from_millis(millis: u64) -> Self {
72        Self::from_micros(millis * 1000)
73    }
74
75    pub const fn from_seconds(seconds: u64) -> Self {
76        Self::from_millis((seconds as u64) * 1000)
77    }
78
79    pub const fn from_minutes(minutes: u64) -> Self {
80        Self::from_seconds(minutes * 60)
81    }
82
83    pub const fn from_hours(hours: u64) -> Self {
84        Self::from_minutes(60 * hours)
85    }
86
87    pub fn is_zero(&self) -> bool {
88        self.0 == 0
89    }
90
91    /// Get duration in hours (rounded down)
92    pub fn to_hours(self) -> u64 {
93        self.to_seconds() / (60 * 60)
94    }
95
96    /// Get duration in minutes (rounded down)
97    pub fn to_minutes(self) -> u64 {
98        self.to_seconds() / 60
99    }
100
101    /// Get duration in seconds (rounded down)
102    pub fn to_seconds(self) -> u64 {
103        (self.0 / (1_000_000)) as u64
104    }
105
106    pub fn to_millis(self) -> u64 {
107        (self.0 / 1_000) as u64
108    }
109
110    pub fn as_micros(&self) -> u64 {
111        self.0
112    }
113
114    pub fn as_millis_f64(&self) -> f64 {
115        (self.0 as f64) / 1_000.0
116    }
117
118    pub fn as_seconds_f64(&self) -> f64 {
119        (self.0 as f64) / (1_000_000.0)
120    }
121}
122
123impl std::ops::Add<Duration> for Time {
124    type Output = Self;
125
126    fn add(self, other: Duration) -> Self {
127        Self(self.0 + other.0)
128    }
129}
130
131impl std::ops::AddAssign<Duration> for Duration {
132    fn add_assign(&mut self, other: Duration) {
133        self.0 += other.0
134    }
135}
136
137impl std::ops::Add for Duration {
138    type Output = Self;
139
140    fn add(self, other: Self) -> Self {
141        Self(self.0 + other.0)
142    }
143}
144
145impl std::ops::Sub for Duration {
146    type Output = Self;
147
148    fn sub(self, other: Self) -> Self {
149        Self(self.0 - other.0)
150    }
151}
152
153impl std::ops::Sub<Self> for Time {
154    type Output = Duration;
155
156    fn sub(self, other: Self) -> Duration {
157        Duration(self.0 - other.0)
158    }
159}
160
161impl std::ops::Sub<Duration> for Time {
162    type Output = Self;
163
164    fn sub(self, other: Duration) -> Self {
165        Self(self.0 - other.0)
166    }
167}
168
169impl std::fmt::Display for Duration {
170    fn fmt(&self, w: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
171        write!(w, "{}μs", self.0)
172    }
173}
174
175impl std::fmt::Display for Time {
176    fn fmt(&self, w: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
177        let hrs = self.to_hours();
178        let minutes = self.to_minutes() - hrs * 60;
179        let secs = self.to_seconds() - minutes * 60 - hrs * 60 * 60;
180        let millis = self.as_millis_f64() % 1000.0;
181
182        if hrs > 0 {
183            write!(w, "{hrs:02}h ")?;
184        }
185        if minutes > 0 {
186            write!(w, "{minutes:02}min ")?;
187        }
188
189        write!(w, "{secs:02}s {millis:.3}ms")
190    }
191}
192
193#[cfg(test)]
194mod tests {
195    use super::{Duration, Time};
196
197    #[test]
198    fn duration_from_seconds() {
199        let duration = Duration::from_seconds(2);
200
201        assert_eq!(2, duration.to_seconds());
202        assert_eq!(2_000, duration.to_millis());
203        assert_eq!(2_000_000, duration.as_micros());
204    }
205
206    #[test]
207    fn time_from_seconds() {
208        let time = Time::from_seconds(2);
209
210        assert_eq!(2, time.to_seconds());
211        assert_eq!(2_000, time.to_millis());
212        assert_eq!(2_000_000, time.as_micros());
213    }
214}