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)]
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) -> Result<(), EncodeError> {
193 self.0.encode(w, crate::lite::Version::Lite01)?;
195 Ok(())
196 }
197
198 pub fn decode<R: bytes::Buf>(r: &mut R) -> Result<Self, Error> {
199 let v = VarInt::decode(r, crate::lite::Version::Lite01)?;
201 Ok(Self(v))
202 }
203}
204
205impl<const SCALE: u64> TryFrom<std::time::Duration> for Timescale<SCALE> {
206 type Error = TimeOverflow;
207
208 fn try_from(duration: std::time::Duration) -> Result<Self, Self::Error> {
209 Self::from_scale_u128(duration.as_nanos(), 1_000_000_000)
210 }
211}
212
213impl<const SCALE: u64> From<Timescale<SCALE>> for std::time::Duration {
214 fn from(time: Timescale<SCALE>) -> Self {
215 std::time::Duration::new(time.as_secs(), (time.as_nanos() % 1_000_000_000) as u32)
216 }
217}
218
219impl<const SCALE: u64> std::fmt::Debug for Timescale<SCALE> {
220 #[allow(clippy::manual_is_multiple_of)] fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 let nanos = self.as_nanos();
223
224 if nanos % 1_000_000_000 == 0 {
227 write!(f, "{}s", nanos / 1_000_000_000)
228 } else if nanos % 1_000_000 == 0 {
229 write!(f, "{}ms", nanos / 1_000_000)
230 } else if nanos % 1_000 == 0 {
231 write!(f, "{}µs", nanos / 1_000)
232 } else {
233 write!(f, "{}ns", nanos)
234 }
235 }
236}
237
238impl<const SCALE: u64> std::ops::Add for Timescale<SCALE> {
239 type Output = Self;
240
241 fn add(self, rhs: Self) -> Self {
242 self.checked_add(rhs).expect("time overflow")
243 }
244}
245
246impl<const SCALE: u64> std::ops::AddAssign for Timescale<SCALE> {
247 fn add_assign(&mut self, rhs: Self) {
248 *self = *self + rhs;
249 }
250}
251
252impl<const SCALE: u64> std::ops::Sub for Timescale<SCALE> {
253 type Output = Self;
254
255 fn sub(self, rhs: Self) -> Self {
256 self.checked_sub(rhs).expect("time overflow")
257 }
258}
259
260impl<const SCALE: u64> std::ops::SubAssign for Timescale<SCALE> {
261 fn sub_assign(&mut self, rhs: Self) {
262 *self = *self - rhs;
263 }
264}
265
266static TIME_ANCHOR: LazyLock<(std::time::Instant, SystemTime)> = LazyLock::new(|| {
268 let jitter = std::time::Duration::from_millis(rand::rng().random_range(0..69_420));
272 (std::time::Instant::now(), SystemTime::now() - jitter)
273});
274
275impl<const SCALE: u64> From<std::time::Instant> for Timescale<SCALE> {
277 fn from(instant: std::time::Instant) -> Self {
278 let (anchor_instant, anchor_system) = *TIME_ANCHOR;
279
280 let system = match instant.checked_duration_since(anchor_instant) {
282 Some(forward) => anchor_system + forward,
283 None => anchor_system - anchor_instant.duration_since(instant),
284 };
285
286 system
289 .duration_since(UNIX_EPOCH)
290 .expect("dude your clock is earlier than 1970")
291 .try_into()
292 .expect("dude your clock is later than 2116")
293 }
294}
295
296impl<const SCALE: u64> From<tokio::time::Instant> for Timescale<SCALE> {
297 fn from(instant: tokio::time::Instant) -> Self {
298 instant.into_std().into()
299 }
300}
301
302impl<const SCALE: u64> Decode<crate::Version> for Timescale<SCALE> {
303 fn decode<R: bytes::Buf>(r: &mut R, version: crate::Version) -> Result<Self, DecodeError> {
304 let v = VarInt::decode(r, version)?;
305 Ok(Self(v))
306 }
307}
308
309impl<const SCALE: u64> Encode<crate::Version> for Timescale<SCALE> {
310 fn encode<W: bytes::BufMut>(&self, w: &mut W, version: crate::Version) -> Result<(), EncodeError> {
311 self.0.encode(w, version)?;
312 Ok(())
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::*;
319
320 #[test]
321 fn test_from_secs() {
322 let time = Time::from_secs(5).unwrap();
323 assert_eq!(time.as_secs(), 5);
324 assert_eq!(time.as_millis(), 5000);
325 assert_eq!(time.as_micros(), 5_000_000);
326 assert_eq!(time.as_nanos(), 5_000_000_000);
327 }
328
329 #[test]
330 fn test_from_millis() {
331 let time = Time::from_millis(5000).unwrap();
332 assert_eq!(time.as_secs(), 5);
333 assert_eq!(time.as_millis(), 5000);
334 }
335
336 #[test]
337 fn test_from_micros() {
338 let time = Time::from_micros(5_000_000).unwrap();
339 assert_eq!(time.as_secs(), 5);
340 assert_eq!(time.as_millis(), 5000);
341 assert_eq!(time.as_micros(), 5_000_000);
342 }
343
344 #[test]
345 fn test_from_nanos() {
346 let time = Time::from_nanos(5_000_000_000).unwrap();
347 assert_eq!(time.as_secs(), 5);
348 assert_eq!(time.as_millis(), 5000);
349 assert_eq!(time.as_micros(), 5_000_000);
350 assert_eq!(time.as_nanos(), 5_000_000_000);
351 }
352
353 #[test]
354 fn test_zero() {
355 let time = Time::ZERO;
356 assert_eq!(time.as_secs(), 0);
357 assert_eq!(time.as_millis(), 0);
358 assert_eq!(time.as_micros(), 0);
359 assert_eq!(time.as_nanos(), 0);
360 assert!(time.is_zero());
361 }
362
363 #[test]
364 fn test_roundtrip_millis() {
365 let values = [0, 1, 100, 1000, 999999, 1_000_000_000];
366 for &val in &values {
367 let time = Time::from_millis(val).unwrap();
368 assert_eq!(time.as_millis(), val as u128);
369 }
370 }
371
372 #[test]
373 fn test_roundtrip_micros() {
374 let values = [0, 1000, 1_000_000, 1_000_000_000];
376 for &val in &values {
377 let time = Time::from_micros(val).unwrap();
378 assert_eq!(time.as_micros(), val as u128);
379 }
380 }
381
382 #[test]
383 fn test_different_scale_seconds() {
384 type TimeInSeconds = Timescale<1>;
385 let time = TimeInSeconds::from_secs(5).unwrap();
386 assert_eq!(time.as_secs(), 5);
387 assert_eq!(time.as_millis(), 5000);
388 }
389
390 #[test]
391 fn test_different_scale_microseconds() {
392 type TimeInMicros = Timescale<1_000_000>;
393 let time = TimeInMicros::from_micros(5_000_000).unwrap();
394 assert_eq!(time.as_secs(), 5);
395 assert_eq!(time.as_micros(), 5_000_000);
396 }
397
398 #[test]
399 fn test_scale_conversion() {
400 let time = Time::from_scale(5000, 1000).unwrap();
402 assert_eq!(time.as_millis(), 5000);
403 assert_eq!(time.as_secs(), 5);
404
405 let time = Time::from_scale(5, 1).unwrap();
407 assert_eq!(time.as_millis(), 5000);
408 assert_eq!(time.as_secs(), 5);
409 }
410
411 #[test]
412 fn test_add() {
413 let a = Time::from_secs(3).unwrap();
414 let b = Time::from_secs(2).unwrap();
415 let c = a + b;
416 assert_eq!(c.as_secs(), 5);
417 assert_eq!(c.as_millis(), 5000);
418 }
419
420 #[test]
421 fn test_sub() {
422 let a = Time::from_secs(5).unwrap();
423 let b = Time::from_secs(2).unwrap();
424 let c = a - b;
425 assert_eq!(c.as_secs(), 3);
426 assert_eq!(c.as_millis(), 3000);
427 }
428
429 #[test]
430 fn test_checked_add() {
431 let a = Time::from_millis(1000).unwrap();
432 let b = Time::from_millis(2000).unwrap();
433 let c = a.checked_add(b).unwrap();
434 assert_eq!(c.as_millis(), 3000);
435 }
436
437 #[test]
438 fn test_checked_sub() {
439 let a = Time::from_millis(5000).unwrap();
440 let b = Time::from_millis(2000).unwrap();
441 let c = a.checked_sub(b).unwrap();
442 assert_eq!(c.as_millis(), 3000);
443 }
444
445 #[test]
446 fn test_checked_sub_underflow() {
447 let a = Time::from_millis(1000).unwrap();
448 let b = Time::from_millis(2000).unwrap();
449 assert!(a.checked_sub(b).is_err());
450 }
451
452 #[test]
453 fn test_max() {
454 let a = Time::from_secs(5).unwrap();
455 let b = Time::from_secs(10).unwrap();
456 assert_eq!(a.max(b), b);
457 assert_eq!(b.max(a), b);
458 }
459
460 #[test]
461 fn test_duration_conversion() {
462 let duration = std::time::Duration::from_secs(5);
463 let time: Time = duration.try_into().unwrap();
464 assert_eq!(time.as_secs(), 5);
465 assert_eq!(time.as_millis(), 5000);
466
467 let duration_back: std::time::Duration = time.into();
468 assert_eq!(duration_back.as_secs(), 5);
469 }
470
471 #[test]
472 fn test_duration_with_nanos() {
473 let duration = std::time::Duration::new(5, 500_000_000); let time: Time = duration.try_into().unwrap();
475 assert_eq!(time.as_millis(), 5500);
476
477 let duration_back: std::time::Duration = time.into();
478 assert_eq!(duration_back.as_millis(), 5500);
479 }
480
481 #[test]
482 fn test_fractional_conversion() {
483 let time = Time::from_millis(1500).unwrap();
485 assert_eq!(time.as_secs(), 1); assert_eq!(time.as_millis(), 1500);
487 assert_eq!(time.as_micros(), 1_500_000);
488 }
489
490 #[test]
491 fn test_precision_loss() {
492 let time = Time::from_micros(1234).unwrap();
496 assert_eq!(time.as_millis(), 1); assert_eq!(time.as_micros(), 1000); }
499
500 #[test]
501 fn test_scale_boundaries() {
502 let time = Time::from_millis(999).unwrap();
504 assert_eq!(time.as_secs(), 0);
505 assert_eq!(time.as_millis(), 999);
506
507 let time = Time::from_millis(1000).unwrap();
508 assert_eq!(time.as_secs(), 1);
509 assert_eq!(time.as_millis(), 1000);
510
511 let time = Time::from_millis(1001).unwrap();
512 assert_eq!(time.as_secs(), 1);
513 assert_eq!(time.as_millis(), 1001);
514 }
515
516 #[test]
517 fn test_large_values() {
518 let large_secs = 1_000_000_000u64; let time = Time::from_secs(large_secs).unwrap();
521 assert_eq!(time.as_secs(), large_secs);
522 }
523
524 #[test]
525 fn test_new() {
526 let time = Time::new(5000); assert_eq!(time.as_millis(), 5000);
528 assert_eq!(time.as_secs(), 5);
529 }
530
531 #[test]
532 fn test_new_u64() {
533 let time = Time::new_u64(5000).unwrap();
534 assert_eq!(time.as_millis(), 5000);
535 }
536
537 #[test]
538 fn test_ordering() {
539 let a = Time::from_secs(1).unwrap();
540 let b = Time::from_secs(2).unwrap();
541 assert!(a < b);
542 assert!(b > a);
543 assert_eq!(a, a);
544 }
545
546 #[test]
547 fn test_unchecked_variants() {
548 let time = Time::from_secs_unchecked(5);
549 assert_eq!(time.as_secs(), 5);
550
551 let time = Time::from_millis_unchecked(5000);
552 assert_eq!(time.as_millis(), 5000);
553
554 let time = Time::from_micros_unchecked(5_000_000);
555 assert_eq!(time.as_micros(), 5_000_000);
556
557 let time = Time::from_nanos_unchecked(5_000_000_000);
558 assert_eq!(time.as_nanos(), 5_000_000_000);
559
560 let time = Time::from_scale_unchecked(5000, 1000);
561 assert_eq!(time.as_millis(), 5000);
562 }
563
564 #[test]
565 fn test_as_scale() {
566 let time = Time::from_secs(1).unwrap();
567 assert_eq!(time.as_scale(1000), 1000);
569 assert_eq!(time.as_scale(1), 1);
571 assert_eq!(time.as_scale(1_000_000), 1_000_000);
573 }
574
575 #[test]
576 fn test_convert_to_finer() {
577 type TimeInMillis = Timescale<1_000>;
579 type TimeInMicros = Timescale<1_000_000>;
580
581 let time_millis = TimeInMillis::from_millis(5000).unwrap();
582 let time_micros: TimeInMicros = time_millis.convert().unwrap();
583
584 assert_eq!(time_micros.as_millis(), 5000);
585 assert_eq!(time_micros.as_micros(), 5_000_000);
586 }
587
588 #[test]
589 fn test_convert_to_coarser() {
590 type TimeInMillis = Timescale<1_000>;
592 type TimeInSeconds = Timescale<1>;
593
594 let time_millis = TimeInMillis::from_millis(5000).unwrap();
595 let time_secs: TimeInSeconds = time_millis.convert().unwrap();
596
597 assert_eq!(time_secs.as_secs(), 5);
598 assert_eq!(time_secs.as_millis(), 5000);
599 }
600
601 #[test]
602 fn test_convert_precision_loss() {
603 type TimeInMillis = Timescale<1_000>;
605 type TimeInSeconds = Timescale<1>;
606
607 let time_millis = TimeInMillis::from_millis(1234).unwrap();
608 let time_secs: TimeInSeconds = time_millis.convert().unwrap();
609
610 assert_eq!(time_secs.as_secs(), 1);
612 assert_eq!(time_secs.as_millis(), 1000); }
614
615 #[test]
616 fn test_convert_roundtrip() {
617 type TimeInMillis = Timescale<1_000>;
619 type TimeInMicros = Timescale<1_000_000>;
620
621 let original = TimeInMillis::from_millis(5000).unwrap();
622 let as_micros: TimeInMicros = original.convert().unwrap();
623 let back_to_millis: TimeInMillis = as_micros.convert().unwrap();
624
625 assert_eq!(original.as_millis(), back_to_millis.as_millis());
626 }
627
628 #[test]
629 fn test_convert_same_scale() {
630 type TimeInMillis = Timescale<1_000>;
632
633 let time = TimeInMillis::from_millis(5000).unwrap();
634 let converted: TimeInMillis = time.convert().unwrap();
635
636 assert_eq!(time.as_millis(), converted.as_millis());
637 }
638
639 #[test]
640 fn test_convert_microseconds_to_nanoseconds() {
641 type TimeInMicros = Timescale<1_000_000>;
642 type TimeInNanos = Timescale<1_000_000_000>;
643
644 let time_micros = TimeInMicros::from_micros(5_000_000).unwrap();
645 let time_nanos: TimeInNanos = time_micros.convert().unwrap();
646
647 assert_eq!(time_nanos.as_micros(), 5_000_000);
648 assert_eq!(time_nanos.as_nanos(), 5_000_000_000);
649 }
650
651 #[test]
652 fn test_convert_custom_scales() {
653 type TimeScale60 = Timescale<60>; type TimeScale90 = Timescale<90>; let time60 = TimeScale60::from_scale(120, 60).unwrap(); let time90: TimeScale90 = time60.convert().unwrap();
659
660 assert_eq!(time60.as_secs(), 2);
662 assert_eq!(time90.as_secs(), 2);
663 }
664
665 #[test]
666 fn test_debug_format_units() {
667 let t = Time::from_millis(100000).unwrap();
671 assert_eq!(format!("{:?}", t), "100s");
672
673 let t = Time::from_millis(1000).unwrap();
674 assert_eq!(format!("{:?}", t), "1s");
675
676 let t = Time::from_millis(100).unwrap();
678 assert_eq!(format!("{:?}", t), "100ms");
679
680 let t = Time::from_millis(5500).unwrap();
681 assert_eq!(format!("{:?}", t), "5500ms");
682
683 let t = Time::ZERO;
685 assert_eq!(format!("{:?}", t), "0s");
686
687 type TimeMicros = Timescale<1_000_000>;
689 let t = TimeMicros::from_micros(1500).unwrap();
690 assert_eq!(format!("{:?}", t), "1500µs");
691
692 let t = TimeMicros::from_micros(1000).unwrap();
693 assert_eq!(format!("{:?}", t), "1ms");
694 }
695}