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