1use serde::{Deserialize, Serialize};
2
3pub const START_TIME: Time = Time(0);
5
6#[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 pub fn to_hours(&self) -> u64 {
36 self.to_seconds() / (60 * 60)
37 }
38
39 pub fn to_minutes(self) -> u64 {
41 self.to_seconds() / 60
42 }
43
44 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 pub fn to_hours(self) -> u64 {
93 self.to_seconds() / (60 * 60)
94 }
95
96 pub fn to_minutes(self) -> u64 {
98 self.to_seconds() / 60
99 }
100
101 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}