1use std::sync::atomic::{AtomicU64, Ordering};
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13#[serde(transparent)]
14pub struct Tick(u64);
15
16impl Tick {
17 pub const ZERO: Tick = Tick(0);
18
19 pub fn new(value: u64) -> Self {
20 Tick(value)
21 }
22
23 pub fn value(self) -> u64 {
24 self.0
25 }
26
27 pub fn increment(self) -> Self {
28 Tick(self.0.saturating_add(1))
29 }
30}
31
32#[derive(Debug)]
42pub struct TickClock {
43 current: AtomicU64,
44}
45
46impl TickClock {
47 pub fn new(start: Tick) -> Self {
48 Self {
49 current: AtomicU64::new(start.value()),
50 }
51 }
52
53 pub fn default_start() -> Self {
54 Self::new(Tick::ZERO)
55 }
56
57 pub fn now_tick(&self) -> Tick {
59 Tick(self.current.load(Ordering::Relaxed))
60 }
61
62 pub fn advance(&self, delta: u64) -> Tick {
64 let next = self.current.fetch_add(delta, Ordering::Relaxed) + delta;
65 Tick(next)
66 }
67
68 pub fn tick(&self) -> Tick {
70 self.advance(1)
71 }
72}
73
74impl Default for TickClock {
75 fn default() -> Self {
76 Self::default_start()
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn monotonic_ticks() {
86 let clock = TickClock::default();
87 assert_eq!(clock.now_tick(), Tick::ZERO);
88 let t1 = clock.tick();
89 let t2 = clock.tick();
90 assert!(t2.value() > t1.value());
91 }
92}