1use std::{
2 mem,
3 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign},
4};
5
6const NANOS_PER_MICRO: i64 = 1_000;
7const NANOS_PER_MILLI: i64 = NANOS_PER_MICRO * 1_000;
8const NANOS_PER_SEC: i64 = NANOS_PER_MILLI * 1_000;
9
10fn zero_std_instant() -> std::time::Instant {
11 if cfg!(unix) || cfg!(windows) {
12 unsafe { mem::zeroed() }
15 } else {
16 unimplemented!()
17 }
18}
19
20#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[repr(transparent)]
23pub struct Duration {
24 pub nanos: i64,
25}
26
27impl Duration {
28 pub const fn new(nanos: i64) -> Self {
29 Self { nanos }
30 }
31
32 pub const fn zero() -> Self {
33 Self::new(0)
34 }
35
36 pub const fn from_secs(secs: i64) -> Self {
37 Self::new(secs * NANOS_PER_SEC)
38 }
39
40 pub const fn from_millis(millis: i64) -> Self {
41 Self::new(millis * NANOS_PER_MILLI)
42 }
43
44 pub const fn from_micros(micros: i64) -> Self {
45 Self::new(micros * NANOS_PER_MICRO)
46 }
47
48 pub fn from_secs_f32(secs: f32) -> Self {
49 Self::new((secs * NANOS_PER_SEC as f32).round() as i64)
50 }
51
52 pub fn from_secs_f64(secs: f64) -> Self {
53 Self::new((secs * NANOS_PER_SEC as f64).round() as i64)
54 }
55
56 pub fn as_secs_f32(self) -> f32 {
57 self.nanos as f32 / NANOS_PER_SEC as f32
58 }
59
60 pub fn as_secs_f64(self) -> f64 {
61 self.nanos as f64 / NANOS_PER_SEC as f64
62 }
63
64 pub fn div_duration_f32(self, rhs: Self) -> f32 {
65 self.as_secs_f32() / rhs.as_secs_f32()
66 }
67
68 pub fn div_duration_f64(self, rhs: Self) -> f64 {
69 self.as_secs_f64() / rhs.as_secs_f64()
70 }
71
72 pub fn clamp(self, min: Duration, max: Duration) -> Self {
73 assert!(min <= max);
74 if self < min {
75 min
76 } else if self > max {
77 max
78 } else {
79 self
80 }
81 }
82
83 pub fn from_std_duration(std: std::time::Duration) -> Self {
84 let result = std.as_nanos();
85 debug_assert!(result <= i64::max_value() as u128);
86 Self::new(result as _)
87 }
88
89 pub fn into_std_duration(self) -> std::time::Duration {
90 debug_assert!(self.nanos >= 0);
91 std::time::Duration::from_nanos(self.nanos as _)
92 }
93}
94
95impl From<std::time::Duration> for Duration {
96 fn from(std: std::time::Duration) -> Self {
97 Self::from_std_duration(std)
98 }
99}
100
101impl Into<std::time::Duration> for Duration {
102 fn into(self) -> std::time::Duration {
103 self.into_std_duration()
104 }
105}
106
107impl Add for Duration {
108 type Output = Self;
109 fn add(self, rhs: Self) -> Self {
110 Self::new(self.nanos + rhs.nanos)
111 }
112}
113
114impl AddAssign for Duration {
115 fn add_assign(&mut self, rhs: Duration) {
116 *self = *self + rhs
117 }
118}
119
120impl Sub for Duration {
121 type Output = Self;
122 fn sub(self, rhs: Self) -> Self {
123 Self::new(self.nanos - rhs.nanos)
124 }
125}
126
127impl SubAssign for Duration {
128 fn sub_assign(&mut self, rhs: Duration) {
129 *self = *self - rhs
130 }
131}
132
133impl Neg for Duration {
134 type Output = Self;
135 fn neg(self) -> Self {
136 Duration::zero() - self
137 }
138}
139
140impl Mul<i32> for Duration {
141 type Output = Self;
142 fn mul(self, rhs: i32) -> Self {
143 Self::new(self.nanos * rhs as i64)
144 }
145}
146
147impl Mul<Duration> for i32 {
148 type Output = Duration;
149 fn mul(self, rhs: Duration) -> Duration {
150 rhs * self
151 }
152}
153
154impl MulAssign<i32> for Duration {
155 fn mul_assign(&mut self, rhs: i32) {
156 *self = *self * rhs
157 }
158}
159
160impl Mul<f32> for Duration {
161 type Output = Self;
162 fn mul(self, rhs: f32) -> Self {
163 Self::from_secs_f32(self.as_secs_f32() * rhs)
164 }
165}
166
167impl Mul<Duration> for f32 {
168 type Output = Duration;
169 fn mul(self, rhs: Duration) -> Duration {
170 rhs * self
171 }
172}
173
174impl MulAssign<f32> for Duration {
175 fn mul_assign(&mut self, rhs: f32) {
176 *self = *self * rhs
177 }
178}
179
180impl Mul<f64> for Duration {
181 type Output = Self;
182 fn mul(self, rhs: f64) -> Self {
183 Self::from_secs_f64(self.as_secs_f64() * rhs)
184 }
185}
186
187impl Mul<Duration> for f64 {
188 type Output = Duration;
189 fn mul(self, rhs: Duration) -> Duration {
190 rhs * self
191 }
192}
193
194impl MulAssign<f64> for Duration {
195 fn mul_assign(&mut self, rhs: f64) {
196 *self = *self * rhs
197 }
198}
199
200impl Div<i32> for Duration {
201 type Output = Self;
202 fn div(self, rhs: i32) -> Self {
203 Self::new(self.nanos / rhs as i64)
204 }
205}
206
207impl DivAssign<i32> for Duration {
208 fn div_assign(&mut self, rhs: i32) {
209 *self = *self / rhs
210 }
211}
212
213impl Div<f32> for Duration {
214 type Output = Self;
215 fn div(self, rhs: f32) -> Self {
216 Self::from_secs_f32(self.as_secs_f32() / rhs)
217 }
218}
219
220impl DivAssign<f32> for Duration {
221 fn div_assign(&mut self, rhs: f32) {
222 *self = *self / rhs
223 }
224}
225
226impl Div<f64> for Duration {
227 type Output = Self;
228 fn div(self, rhs: f64) -> Self {
229 Self::from_secs_f64(self.as_secs_f64() / rhs)
230 }
231}
232
233impl DivAssign<f64> for Duration {
234 fn div_assign(&mut self, rhs: f64) {
235 *self = *self / rhs
236 }
237}
238
239impl Rem for Duration {
240 type Output = Self;
241 fn rem(self, rhs: Self) -> Self {
242 Self::new(self.nanos % rhs.nanos)
243 }
244}
245
246impl RemAssign for Duration {
247 fn rem_assign(&mut self, rhs: Self) {
248 *self = *self % rhs
249 }
250}
251
252#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
253#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
254#[repr(transparent)]
255pub struct TimePoint {
256 pub nanos_since_zero: i64,
257}
258
259impl TimePoint {
260 pub const fn new(nanos_since_zero: i64) -> Self {
262 Self { nanos_since_zero }
263 }
264
265 pub const fn zero() -> Self {
266 Self::new(0)
267 }
268
269 pub fn from_secs_f32(secs_since_zero: f32) -> Self {
270 Self::zero() + Duration::from_secs_f32(secs_since_zero)
271 }
272
273 pub fn from_secs_f64(secs_since_zero: f64) -> Self {
274 Self::zero() + Duration::from_secs_f64(secs_since_zero)
275 }
276
277 pub fn as_secs_f32(self) -> f32 {
278 self.duration_from_zero().as_secs_f32()
279 }
280
281 pub fn as_secs_f64(self) -> f64 {
282 self.duration_from_zero().as_secs_f64()
283 }
284
285 pub fn duration_from_zero(self) -> Duration {
286 self - Self::zero()
287 }
288
289 pub fn from_std_instant(rhs: std::time::Instant) -> Self {
290 Self::new(Duration::from_std_duration(rhs - zero_std_instant()).nanos)
291 }
292
293 pub fn into_std_instant(self) -> std::time::Instant {
294 zero_std_instant() + self.duration_from_zero().into_std_duration()
295 }
296}
297
298impl From<std::time::Instant> for TimePoint {
299 fn from(std: std::time::Instant) -> Self {
300 Self::from_std_instant(std)
301 }
302}
303
304impl Into<std::time::Instant> for TimePoint {
305 fn into(self) -> std::time::Instant {
306 self.into_std_instant()
307 }
308}
309
310impl Add<Duration> for TimePoint {
311 type Output = TimePoint;
312 fn add(self, rhs: Duration) -> Self {
313 Self::new(self.nanos_since_zero + rhs.nanos)
314 }
315}
316
317impl AddAssign<Duration> for TimePoint {
318 fn add_assign(&mut self, rhs: Duration) {
319 *self = *self + rhs
320 }
321}
322
323impl Add<TimePoint> for Duration {
324 type Output = TimePoint;
325 fn add(self, rhs: TimePoint) -> TimePoint {
326 rhs + self
327 }
328}
329
330impl Sub<Duration> for TimePoint {
331 type Output = TimePoint;
332 fn sub(self, rhs: Duration) -> Self {
333 self + -rhs
334 }
335}
336
337impl SubAssign<Duration> for TimePoint {
338 fn sub_assign(&mut self, rhs: Duration) {
339 *self = *self - rhs
340 }
341}
342
343impl Sub<TimePoint> for TimePoint {
344 type Output = Duration;
345 fn sub(self, rhs: TimePoint) -> Duration {
346 Duration::new(self.nanos_since_zero - rhs.nanos_since_zero)
347 }
348}
349
350#[test]
351fn std_compat() {
352 let now = std::time::Instant::now();
353 let now2 = TimePoint::from_std_instant(now).into_std_instant();
354 assert_eq!(now, now2);
355
356 let duration = std::time::Duration::from_millis(1_000_042);
357 let duration2 = Duration::from_std_duration(duration).into_std_duration();
358 assert_eq!(duration, duration2);
359
360 let std_now = std::time::Instant::now();
361 let std_now_plus = std_now + std::time::Duration::from_millis(1_000_042);
362 let now = TimePoint::from_std_instant(std_now);
363 let now_plus = now + Duration::from_millis(1_000_042);
364 assert_eq!(std_now_plus, now_plus.into_std_instant());
365 assert_eq!(TimePoint::from_std_instant(std_now_plus), now_plus);
366}