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