reifydb_runtime/clock/
native.rs1use std::{
7 sync::{
8 Arc,
9 atomic::{AtomicU64, Ordering},
10 },
11 time::{Duration, SystemTime, UNIX_EPOCH},
12};
13
14#[inline(always)]
15fn platform_now_nanos() -> u128 {
16 SystemTime::now().duration_since(UNIX_EPOCH).expect("System time is before Unix epoch").as_nanos()
17}
18
19#[derive(Clone)]
21pub enum Clock {
22 Real,
24 Mock(MockClock),
26}
27
28impl Clock {
29 pub fn now_nanos(&self) -> u128 {
31 match self {
32 Clock::Real => platform_now_nanos(),
33 Clock::Mock(mock) => mock.now_nanos(),
34 }
35 }
36
37 pub fn now_micros(&self) -> u64 {
39 (self.now_nanos() / 1_000) as u64
40 }
41
42 pub fn now_millis(&self) -> u64 {
44 (self.now_nanos() / 1_000_000) as u64
45 }
46
47 pub fn now_secs(&self) -> u64 {
49 (self.now_nanos() / 1_000_000_000) as u64
50 }
51
52 pub fn instant(&self) -> Instant {
53 match self {
54 Clock::Real => Instant {
55 inner: InstantInner::Real(std::time::Instant::now()),
56 },
57 Clock::Mock(mock) => Instant {
58 inner: InstantInner::Mock {
59 captured_nanos: mock.now_nanos(),
60 clock: mock.clone(),
61 },
62 },
63 }
64 }
65}
66
67impl Default for Clock {
68 fn default() -> Self {
69 Clock::Real
70 }
71}
72
73#[derive(Clone)]
75pub struct MockClock {
76 inner: Arc<MockClockInner>,
77}
78
79struct MockClockInner {
80 time_high: AtomicU64,
82 time_low: AtomicU64,
83}
84
85impl MockClock {
86 pub fn new(initial_nanos: u128) -> Self {
88 Self {
89 inner: Arc::new(MockClockInner {
90 time_high: AtomicU64::new((initial_nanos >> 64) as u64),
91 time_low: AtomicU64::new(initial_nanos as u64),
92 }),
93 }
94 }
95
96 pub fn from_millis(millis: u64) -> Self {
98 Self::new(millis as u128 * 1_000_000)
99 }
100
101 pub fn now_nanos(&self) -> u128 {
103 let high = self.inner.time_high.load(Ordering::Acquire) as u128;
104 let low = self.inner.time_low.load(Ordering::Acquire) as u128;
105 (high << 64) | low
106 }
107
108 pub fn now_micros(&self) -> u64 {
110 (self.now_nanos() / 1_000) as u64
111 }
112
113 pub fn now_millis(&self) -> u64 {
115 (self.now_nanos() / 1_000_000) as u64
116 }
117
118 pub fn now_secs(&self) -> u64 {
120 (self.now_nanos() / 1_000_000_000) as u64
121 }
122
123 pub fn set_nanos(&self, nanos: u128) {
125 self.inner.time_high.store((nanos >> 64) as u64, Ordering::Release);
126 self.inner.time_low.store(nanos as u64, Ordering::Release);
127 }
128
129 pub fn set_micros(&self, micros: u64) {
131 self.set_nanos(micros as u128 * 1_000);
132 }
133
134 pub fn set_millis(&self, millis: u64) {
136 self.set_nanos(millis as u128 * 1_000_000);
137 }
138
139 pub fn advance_nanos(&self, nanos: u128) {
141 self.set_nanos(self.now_nanos() + nanos);
142 }
143
144 pub fn advance_micros(&self, micros: u64) {
146 self.advance_nanos(micros as u128 * 1_000);
147 }
148
149 pub fn advance_millis(&self, millis: u64) {
151 self.advance_nanos(millis as u128 * 1_000_000);
152 }
153}
154
155#[derive(Clone)]
156enum InstantInner {
157 Real(std::time::Instant),
158 Mock {
159 captured_nanos: u128,
160 clock: MockClock,
161 },
162}
163
164#[derive(Clone)]
165pub struct Instant {
166 inner: InstantInner,
167}
168
169impl Instant {
170 #[inline]
171 pub fn elapsed(&self) -> Duration {
172 match &self.inner {
173 InstantInner::Real(instant) => instant.elapsed(),
174 InstantInner::Mock {
175 captured_nanos,
176 clock,
177 } => {
178 let now = clock.now_nanos();
179 let elapsed_nanos = now.saturating_sub(*captured_nanos);
180 Duration::from_nanos(elapsed_nanos as u64)
181 }
182 }
183 }
184
185 #[inline]
186 pub fn duration_since(&self, earlier: Instant) -> Duration {
187 match (&self.inner, &earlier.inner) {
188 (InstantInner::Real(this), InstantInner::Real(other)) => this.duration_since(*other),
189 (
190 InstantInner::Mock {
191 captured_nanos: this_nanos,
192 ..
193 },
194 InstantInner::Mock {
195 captured_nanos: other_nanos,
196 ..
197 },
198 ) => {
199 let elapsed = this_nanos.saturating_sub(*other_nanos);
200 Duration::from_nanos(elapsed as u64)
201 }
202 _ => panic!("Cannot compare instants from different clock types"),
203 }
204 }
205}
206
207impl std::fmt::Debug for Instant {
208 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209 match &self.inner {
210 InstantInner::Real(instant) => f.debug_tuple("Instant::Real").field(instant).finish(),
211 InstantInner::Mock {
212 captured_nanos,
213 ..
214 } => f.debug_tuple("Instant::Mock").field(captured_nanos).finish(),
215 }
216 }
217}