time_point/
lib.rs

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        // https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/time.rs
13        // https://github.com/rust-lang/rust/blob/master/src/libstd/sys/windows/time.rs
14        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    /// This does not specifically require using unix time, however, that's probably expected.
261    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}