1use rand::Rng;
2
3use crate::Error;
4use crate::coding::{Decode, DecodeError, Encode, VarInt};
5
6use std::sync::LazyLock;
7use std::time::{SystemTime, UNIX_EPOCH};
8
9pub type Time = Timescale<1_000>;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
15#[error("time overflow")]
16pub struct TimeOverflow;
17
18#[derive(Clone, Default, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct Timescale<const SCALE: u64>(VarInt);
27
28impl<const SCALE: u64> Timescale<SCALE> {
29 pub const MAX: Self = Self(VarInt::MAX);
31
32 pub const ZERO: Self = Self(VarInt::ZERO);
34
35 pub const fn new(value: u32) -> Self {
36 Self(VarInt::from_u32(value))
37 }
38
39 pub const fn new_u64(value: u64) -> Result<Self, TimeOverflow> {
40 match VarInt::from_u64(value) {
41 Some(varint) => Ok(Self(varint)),
42 None => Err(TimeOverflow),
43 }
44 }
45
46 pub const fn from_secs(seconds: u64) -> Result<Self, TimeOverflow> {
48 match seconds.checked_mul(SCALE) {
50 Some(value) => Self::new_u64(value),
51 None => Err(TimeOverflow),
52 }
53 }
54
55 pub const fn from_secs_unchecked(seconds: u64) -> Self {
56 match Self::from_secs(seconds) {
57 Ok(time) => time,
58 Err(_) => panic!("time overflow"),
59 }
60 }
61
62 pub const fn from_millis(millis: u64) -> Result<Self, TimeOverflow> {
64 Self::from_scale(millis, 1000)
65 }
66
67 pub const fn from_millis_unchecked(millis: u64) -> Self {
68 Self::from_scale_unchecked(millis, 1000)
69 }
70
71 pub const fn from_micros(micros: u64) -> Result<Self, TimeOverflow> {
72 Self::from_scale(micros, 1_000_000)
73 }
74
75 pub const fn from_micros_unchecked(micros: u64) -> Self {
76 Self::from_scale_unchecked(micros, 1_000_000)
77 }
78
79 pub const fn from_nanos(nanos: u64) -> Result<Self, TimeOverflow> {
80 Self::from_scale(nanos, 1_000_000_000)
81 }
82
83 pub const fn from_nanos_unchecked(nanos: u64) -> Self {
84 Self::from_scale_unchecked(nanos, 1_000_000_000)
85 }
86
87 pub const fn from_scale(value: u64, scale: u64) -> Result<Self, TimeOverflow> {
88 match VarInt::from_u128(value as u128 * SCALE as u128 / scale as u128) {
89 Some(varint) => Ok(Self(varint)),
90 None => Err(TimeOverflow),
91 }
92 }
93
94 pub const fn from_scale_u128(value: u128, scale: u64) -> Result<Self, TimeOverflow> {
95 match value.checked_mul(SCALE as u128) {
96 Some(value) => match VarInt::from_u128(value / scale as u128) {
97 Some(varint) => Ok(Self(varint)),
98 None => Err(TimeOverflow),
99 },
100 None => Err(TimeOverflow),
101 }
102 }
103
104 pub const fn from_scale_unchecked(value: u64, scale: u64) -> Self {
105 match Self::from_scale(value, scale) {
106 Ok(time) => time,
107 Err(_) => panic!("time overflow"),
108 }
109 }
110
111 pub const fn as_secs(self) -> u64 {
113 self.0.into_inner() / SCALE
114 }
115
116 pub const fn as_millis(self) -> u128 {
120 self.as_scale(1000)
121 }
122
123 pub const fn as_micros(self) -> u128 {
125 self.as_scale(1_000_000)
126 }
127
128 pub const fn as_nanos(self) -> u128 {
130 self.as_scale(1_000_000_000)
131 }
132
133 pub const fn as_scale(self, scale: u64) -> u128 {
134 self.0.into_inner() as u128 * scale as u128 / SCALE as u128
135 }
136
137 pub const fn max(self, other: Self) -> Self {
139 if self.0.into_inner() > other.0.into_inner() {
140 self
141 } else {
142 other
143 }
144 }
145
146 pub const fn checked_add(self, rhs: Self) -> Result<Self, TimeOverflow> {
147 let lhs = self.0.into_inner();
148 let rhs = rhs.0.into_inner();
149 match lhs.checked_add(rhs) {
150 Some(result) => Self::new_u64(result),
151 None => Err(TimeOverflow),
152 }
153 }
154
155 pub const fn checked_sub(self, rhs: Self) -> Result<Self, TimeOverflow> {
156 let lhs = self.0.into_inner();
157 let rhs = rhs.0.into_inner();
158 match lhs.checked_sub(rhs) {
159 Some(result) => Self::new_u64(result),
160 None => Err(TimeOverflow),
161 }
162 }
163
164 pub const fn is_zero(self) -> bool {
165 self.0.into_inner() == 0
166 }
167
168 pub fn now() -> Self {
169 tokio::time::Instant::now().into()
171 }
172
173 pub const fn convert<const NEW_SCALE: u64>(self) -> Result<Timescale<NEW_SCALE>, TimeOverflow> {
178 let value = self.0.into_inner();
179 match (value as u128).checked_mul(NEW_SCALE as u128) {
181 Some(v) => match v.checked_div(SCALE as u128) {
182 Some(v) => match VarInt::from_u128(v) {
183 Some(varint) => Ok(Timescale(varint)),
184 None => Err(TimeOverflow),
185 },
186 None => Err(TimeOverflow),
187 },
188 None => Err(TimeOverflow),
189 }
190 }
191
192 pub fn encode<W: bytes::BufMut>(&self, w: &mut W) {
193 self.0.encode(w, ());
194 }
195
196 pub fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, Error> {
197 let v = VarInt::decode(r, ())?;
198 Ok(Self(v))
199 }
200}
201
202impl<const SCALE: u64> TryFrom<std::time::Duration> for Timescale<SCALE> {
203 type Error = TimeOverflow;
204
205 fn try_from(duration: std::time::Duration) -> Result<Self, Self::Error> {
206 Self::from_scale_u128(duration.as_nanos(), 1_000_000_000)
207 }
208}
209
210impl<const SCALE: u64> From<Timescale<SCALE>> for std::time::Duration {
211 fn from(time: Timescale<SCALE>) -> Self {
212 std::time::Duration::new(time.as_secs(), (time.as_nanos() % 1_000_000_000) as u32)
213 }
214}
215
216impl<const SCALE: u64> std::fmt::Debug for Timescale<SCALE> {
217 #[allow(clippy::manual_is_multiple_of)] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 let nanos = self.as_nanos();
220
221 if nanos % 1_000_000_000 == 0 {
224 write!(f, "{}s", nanos / 1_000_000_000)
225 } else if nanos % 1_000_000 == 0 {
226 write!(f, "{}ms", nanos / 1_000_000)
227 } else if nanos % 1_000 == 0 {
228 write!(f, "{}µs", nanos / 1_000)
229 } else {
230 write!(f, "{}ns", nanos)
231 }
232 }
233}
234
235impl<const SCALE: u64> std::ops::Add for Timescale<SCALE> {
236 type Output = Self;
237
238 fn add(self, rhs: Self) -> Self {
239 self.checked_add(rhs).expect("time overflow")
240 }
241}
242
243impl<const SCALE: u64> std::ops::AddAssign for Timescale<SCALE> {
244 fn add_assign(&mut self, rhs: Self) {
245 *self = *self + rhs;
246 }
247}
248
249impl<const SCALE: u64> std::ops::Sub for Timescale<SCALE> {
250 type Output = Self;
251
252 fn sub(self, rhs: Self) -> Self {
253 self.checked_sub(rhs).expect("time overflow")
254 }
255}
256
257impl<const SCALE: u64> std::ops::SubAssign for Timescale<SCALE> {
258 fn sub_assign(&mut self, rhs: Self) {
259 *self = *self - rhs;
260 }
261}
262
263static TIME_ANCHOR: LazyLock<(std::time::Instant, SystemTime)> = LazyLock::new(|| {
265 let jitter = std::time::Duration::from_millis(rand::rng().random_range(0..69_420));
269 (std::time::Instant::now(), SystemTime::now() - jitter)
270});
271
272impl<const SCALE: u64> From<std::time::Instant> for Timescale<SCALE> {
274 fn from(instant: std::time::Instant) -> Self {
275 let (anchor_instant, anchor_system) = *TIME_ANCHOR;
276
277 let system = match instant.checked_duration_since(anchor_instant) {
279 Some(forward) => anchor_system + forward,
280 None => anchor_system - anchor_instant.duration_since(instant),
281 };
282
283 system
286 .duration_since(UNIX_EPOCH)
287 .expect("dude your clock is earlier than 1970")
288 .try_into()
289 .expect("dude your clock is later than 2116")
290 }
291}
292
293impl<const SCALE: u64> From<tokio::time::Instant> for Timescale<SCALE> {
294 fn from(instant: tokio::time::Instant) -> Self {
295 instant.into_std().into()
296 }
297}
298
299impl<const SCALE: u64, V> Decode<V> for Timescale<SCALE> {
300 fn decode<R: bytes::Buf>(r: &mut R, version: V) -> Result<Self, DecodeError> {
301 let v = VarInt::decode(r, version)?;
302 Ok(Self(v))
303 }
304}
305
306impl<const SCALE: u64, V> Encode<V> for Timescale<SCALE> {
307 fn encode<W: bytes::BufMut>(&self, w: &mut W, version: V) {
308 self.0.encode(w, version)
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315
316 #[test]
317 fn test_from_secs() {
318 let time = Time::from_secs(5).unwrap();
319 assert_eq!(time.as_secs(), 5);
320 assert_eq!(time.as_millis(), 5000);
321 assert_eq!(time.as_micros(), 5_000_000);
322 assert_eq!(time.as_nanos(), 5_000_000_000);
323 }
324
325 #[test]
326 fn test_from_millis() {
327 let time = Time::from_millis(5000).unwrap();
328 assert_eq!(time.as_secs(), 5);
329 assert_eq!(time.as_millis(), 5000);
330 }
331
332 #[test]
333 fn test_from_micros() {
334 let time = Time::from_micros(5_000_000).unwrap();
335 assert_eq!(time.as_secs(), 5);
336 assert_eq!(time.as_millis(), 5000);
337 assert_eq!(time.as_micros(), 5_000_000);
338 }
339
340 #[test]
341 fn test_from_nanos() {
342 let time = Time::from_nanos(5_000_000_000).unwrap();
343 assert_eq!(time.as_secs(), 5);
344 assert_eq!(time.as_millis(), 5000);
345 assert_eq!(time.as_micros(), 5_000_000);
346 assert_eq!(time.as_nanos(), 5_000_000_000);
347 }
348
349 #[test]
350 fn test_zero() {
351 let time = Time::ZERO;
352 assert_eq!(time.as_secs(), 0);
353 assert_eq!(time.as_millis(), 0);
354 assert_eq!(time.as_micros(), 0);
355 assert_eq!(time.as_nanos(), 0);
356 assert!(time.is_zero());
357 }
358
359 #[test]
360 fn test_roundtrip_millis() {
361 let values = [0, 1, 100, 1000, 999999, 1_000_000_000];
362 for &val in &values {
363 let time = Time::from_millis(val).unwrap();
364 assert_eq!(time.as_millis(), val as u128);
365 }
366 }
367
368 #[test]
369 fn test_roundtrip_micros() {
370 let values = [0, 1000, 1_000_000, 1_000_000_000];
372 for &val in &values {
373 let time = Time::from_micros(val).unwrap();
374 assert_eq!(time.as_micros(), val as u128);
375 }
376 }
377
378 #[test]
379 fn test_different_scale_seconds() {
380 type TimeInSeconds = Timescale<1>;
381 let time = TimeInSeconds::from_secs(5).unwrap();
382 assert_eq!(time.as_secs(), 5);
383 assert_eq!(time.as_millis(), 5000);
384 }
385
386 #[test]
387 fn test_different_scale_microseconds() {
388 type TimeInMicros = Timescale<1_000_000>;
389 let time = TimeInMicros::from_micros(5_000_000).unwrap();
390 assert_eq!(time.as_secs(), 5);
391 assert_eq!(time.as_micros(), 5_000_000);
392 }
393
394 #[test]
395 fn test_scale_conversion() {
396 let time = Time::from_scale(5000, 1000).unwrap();
398 assert_eq!(time.as_millis(), 5000);
399 assert_eq!(time.as_secs(), 5);
400
401 let time = Time::from_scale(5, 1).unwrap();
403 assert_eq!(time.as_millis(), 5000);
404 assert_eq!(time.as_secs(), 5);
405 }
406
407 #[test]
408 fn test_add() {
409 let a = Time::from_secs(3).unwrap();
410 let b = Time::from_secs(2).unwrap();
411 let c = a + b;
412 assert_eq!(c.as_secs(), 5);
413 assert_eq!(c.as_millis(), 5000);
414 }
415
416 #[test]
417 fn test_sub() {
418 let a = Time::from_secs(5).unwrap();
419 let b = Time::from_secs(2).unwrap();
420 let c = a - b;
421 assert_eq!(c.as_secs(), 3);
422 assert_eq!(c.as_millis(), 3000);
423 }
424
425 #[test]
426 fn test_checked_add() {
427 let a = Time::from_millis(1000).unwrap();
428 let b = Time::from_millis(2000).unwrap();
429 let c = a.checked_add(b).unwrap();
430 assert_eq!(c.as_millis(), 3000);
431 }
432
433 #[test]
434 fn test_checked_sub() {
435 let a = Time::from_millis(5000).unwrap();
436 let b = Time::from_millis(2000).unwrap();
437 let c = a.checked_sub(b).unwrap();
438 assert_eq!(c.as_millis(), 3000);
439 }
440
441 #[test]
442 fn test_checked_sub_underflow() {
443 let a = Time::from_millis(1000).unwrap();
444 let b = Time::from_millis(2000).unwrap();
445 assert!(a.checked_sub(b).is_err());
446 }
447
448 #[test]
449 fn test_max() {
450 let a = Time::from_secs(5).unwrap();
451 let b = Time::from_secs(10).unwrap();
452 assert_eq!(a.max(b), b);
453 assert_eq!(b.max(a), b);
454 }
455
456 #[test]
457 fn test_duration_conversion() {
458 let duration = std::time::Duration::from_secs(5);
459 let time: Time = duration.try_into().unwrap();
460 assert_eq!(time.as_secs(), 5);
461 assert_eq!(time.as_millis(), 5000);
462
463 let duration_back: std::time::Duration = time.into();
464 assert_eq!(duration_back.as_secs(), 5);
465 }
466
467 #[test]
468 fn test_duration_with_nanos() {
469 let duration = std::time::Duration::new(5, 500_000_000); let time: Time = duration.try_into().unwrap();
471 assert_eq!(time.as_millis(), 5500);
472
473 let duration_back: std::time::Duration = time.into();
474 assert_eq!(duration_back.as_millis(), 5500);
475 }
476
477 #[test]
478 fn test_fractional_conversion() {
479 let time = Time::from_millis(1500).unwrap();
481 assert_eq!(time.as_secs(), 1); assert_eq!(time.as_millis(), 1500);
483 assert_eq!(time.as_micros(), 1_500_000);
484 }
485
486 #[test]
487 fn test_precision_loss() {
488 let time = Time::from_micros(1234).unwrap();
492 assert_eq!(time.as_millis(), 1); assert_eq!(time.as_micros(), 1000); }
495
496 #[test]
497 fn test_scale_boundaries() {
498 let time = Time::from_millis(999).unwrap();
500 assert_eq!(time.as_secs(), 0);
501 assert_eq!(time.as_millis(), 999);
502
503 let time = Time::from_millis(1000).unwrap();
504 assert_eq!(time.as_secs(), 1);
505 assert_eq!(time.as_millis(), 1000);
506
507 let time = Time::from_millis(1001).unwrap();
508 assert_eq!(time.as_secs(), 1);
509 assert_eq!(time.as_millis(), 1001);
510 }
511
512 #[test]
513 fn test_large_values() {
514 let large_secs = 1_000_000_000u64; let time = Time::from_secs(large_secs).unwrap();
517 assert_eq!(time.as_secs(), large_secs);
518 }
519
520 #[test]
521 fn test_new() {
522 let time = Time::new(5000); assert_eq!(time.as_millis(), 5000);
524 assert_eq!(time.as_secs(), 5);
525 }
526
527 #[test]
528 fn test_new_u64() {
529 let time = Time::new_u64(5000).unwrap();
530 assert_eq!(time.as_millis(), 5000);
531 }
532
533 #[test]
534 fn test_ordering() {
535 let a = Time::from_secs(1).unwrap();
536 let b = Time::from_secs(2).unwrap();
537 assert!(a < b);
538 assert!(b > a);
539 assert_eq!(a, a);
540 }
541
542 #[test]
543 fn test_unchecked_variants() {
544 let time = Time::from_secs_unchecked(5);
545 assert_eq!(time.as_secs(), 5);
546
547 let time = Time::from_millis_unchecked(5000);
548 assert_eq!(time.as_millis(), 5000);
549
550 let time = Time::from_micros_unchecked(5_000_000);
551 assert_eq!(time.as_micros(), 5_000_000);
552
553 let time = Time::from_nanos_unchecked(5_000_000_000);
554 assert_eq!(time.as_nanos(), 5_000_000_000);
555
556 let time = Time::from_scale_unchecked(5000, 1000);
557 assert_eq!(time.as_millis(), 5000);
558 }
559
560 #[test]
561 fn test_as_scale() {
562 let time = Time::from_secs(1).unwrap();
563 assert_eq!(time.as_scale(1000), 1000);
565 assert_eq!(time.as_scale(1), 1);
567 assert_eq!(time.as_scale(1_000_000), 1_000_000);
569 }
570
571 #[test]
572 fn test_convert_to_finer() {
573 type TimeInMillis = Timescale<1_000>;
575 type TimeInMicros = Timescale<1_000_000>;
576
577 let time_millis = TimeInMillis::from_millis(5000).unwrap();
578 let time_micros: TimeInMicros = time_millis.convert().unwrap();
579
580 assert_eq!(time_micros.as_millis(), 5000);
581 assert_eq!(time_micros.as_micros(), 5_000_000);
582 }
583
584 #[test]
585 fn test_convert_to_coarser() {
586 type TimeInMillis = Timescale<1_000>;
588 type TimeInSeconds = Timescale<1>;
589
590 let time_millis = TimeInMillis::from_millis(5000).unwrap();
591 let time_secs: TimeInSeconds = time_millis.convert().unwrap();
592
593 assert_eq!(time_secs.as_secs(), 5);
594 assert_eq!(time_secs.as_millis(), 5000);
595 }
596
597 #[test]
598 fn test_convert_precision_loss() {
599 type TimeInMillis = Timescale<1_000>;
601 type TimeInSeconds = Timescale<1>;
602
603 let time_millis = TimeInMillis::from_millis(1234).unwrap();
604 let time_secs: TimeInSeconds = time_millis.convert().unwrap();
605
606 assert_eq!(time_secs.as_secs(), 1);
608 assert_eq!(time_secs.as_millis(), 1000); }
610
611 #[test]
612 fn test_convert_roundtrip() {
613 type TimeInMillis = Timescale<1_000>;
615 type TimeInMicros = Timescale<1_000_000>;
616
617 let original = TimeInMillis::from_millis(5000).unwrap();
618 let as_micros: TimeInMicros = original.convert().unwrap();
619 let back_to_millis: TimeInMillis = as_micros.convert().unwrap();
620
621 assert_eq!(original.as_millis(), back_to_millis.as_millis());
622 }
623
624 #[test]
625 fn test_convert_same_scale() {
626 type TimeInMillis = Timescale<1_000>;
628
629 let time = TimeInMillis::from_millis(5000).unwrap();
630 let converted: TimeInMillis = time.convert().unwrap();
631
632 assert_eq!(time.as_millis(), converted.as_millis());
633 }
634
635 #[test]
636 fn test_convert_microseconds_to_nanoseconds() {
637 type TimeInMicros = Timescale<1_000_000>;
638 type TimeInNanos = Timescale<1_000_000_000>;
639
640 let time_micros = TimeInMicros::from_micros(5_000_000).unwrap();
641 let time_nanos: TimeInNanos = time_micros.convert().unwrap();
642
643 assert_eq!(time_nanos.as_micros(), 5_000_000);
644 assert_eq!(time_nanos.as_nanos(), 5_000_000_000);
645 }
646
647 #[test]
648 fn test_convert_custom_scales() {
649 type TimeScale60 = Timescale<60>; type TimeScale90 = Timescale<90>; let time60 = TimeScale60::from_scale(120, 60).unwrap(); let time90: TimeScale90 = time60.convert().unwrap();
655
656 assert_eq!(time60.as_secs(), 2);
658 assert_eq!(time90.as_secs(), 2);
659 }
660
661 #[test]
662 fn test_debug_format_units() {
663 let t = Time::from_millis(100000).unwrap();
667 assert_eq!(format!("{:?}", t), "100s");
668
669 let t = Time::from_millis(1000).unwrap();
670 assert_eq!(format!("{:?}", t), "1s");
671
672 let t = Time::from_millis(100).unwrap();
674 assert_eq!(format!("{:?}", t), "100ms");
675
676 let t = Time::from_millis(5500).unwrap();
677 assert_eq!(format!("{:?}", t), "5500ms");
678
679 let t = Time::ZERO;
681 assert_eq!(format!("{:?}", t), "0s");
682
683 type TimeMicros = Timescale<1_000_000>;
685 let t = TimeMicros::from_micros(1500).unwrap();
686 assert_eq!(format!("{:?}", t), "1500µs");
687
688 let t = TimeMicros::from_micros(1000).unwrap();
689 assert_eq!(format!("{:?}", t), "1ms");
690 }
691}