reifydb_runtime/context/clock/
native.rs1use std::{
7 fmt,
8 sync::{
9 Arc,
10 atomic::{AtomicU64, Ordering},
11 },
12 time,
13 time::{Duration, SystemTime, UNIX_EPOCH},
14};
15
16#[inline(always)]
17fn platform_now_nanos() -> u128 {
18 SystemTime::now().duration_since(UNIX_EPOCH).expect("System time is before Unix epoch").as_nanos()
19}
20
21#[derive(Clone)]
23pub enum Clock {
24 Real,
26 Mock(MockClock),
28}
29
30impl Clock {
31 pub fn now_nanos(&self) -> u128 {
33 match self {
34 Clock::Real => platform_now_nanos(),
35 Clock::Mock(mock) => mock.now_nanos(),
36 }
37 }
38
39 pub fn now_micros(&self) -> u64 {
41 (self.now_nanos() / 1_000) as u64
42 }
43
44 pub fn now_millis(&self) -> u64 {
46 (self.now_nanos() / 1_000_000) as u64
47 }
48
49 pub fn now_secs(&self) -> u64 {
51 (self.now_nanos() / 1_000_000_000) as u64
52 }
53
54 pub fn instant(&self) -> Instant {
55 match self {
56 Clock::Real => Instant {
57 inner: InstantInner::Real(time::Instant::now()),
58 },
59 Clock::Mock(mock) => Instant {
60 inner: InstantInner::Mock {
61 captured_nanos: mock.now_nanos(),
62 clock: mock.clone(),
63 },
64 },
65 }
66 }
67}
68
69impl Default for Clock {
70 fn default() -> Self {
71 Clock::Real
72 }
73}
74
75#[derive(Clone)]
77pub struct MockClock {
78 inner: Arc<MockClockInner>,
79}
80
81struct MockClockInner {
82 time_high: AtomicU64,
84 time_low: AtomicU64,
85}
86
87impl MockClock {
88 pub fn new(initial_nanos: u128) -> Self {
90 Self {
91 inner: Arc::new(MockClockInner {
92 time_high: AtomicU64::new((initial_nanos >> 64) as u64),
93 time_low: AtomicU64::new(initial_nanos as u64),
94 }),
95 }
96 }
97
98 pub fn from_millis(millis: u64) -> Self {
100 Self::new(millis as u128 * 1_000_000)
101 }
102
103 pub fn now_nanos(&self) -> u128 {
105 let high = self.inner.time_high.load(Ordering::Acquire) as u128;
106 let low = self.inner.time_low.load(Ordering::Acquire) as u128;
107 (high << 64) | low
108 }
109
110 pub fn now_micros(&self) -> u64 {
112 (self.now_nanos() / 1_000) as u64
113 }
114
115 pub fn now_millis(&self) -> u64 {
117 (self.now_nanos() / 1_000_000) as u64
118 }
119
120 pub fn now_secs(&self) -> u64 {
122 (self.now_nanos() / 1_000_000_000) as u64
123 }
124
125 pub fn set_nanos(&self, nanos: u128) {
127 self.inner.time_high.store((nanos >> 64) as u64, Ordering::Release);
128 self.inner.time_low.store(nanos as u64, Ordering::Release);
129 }
130
131 pub fn set_micros(&self, micros: u64) {
133 self.set_nanos(micros as u128 * 1_000);
134 }
135
136 pub fn set_millis(&self, millis: u64) {
138 self.set_nanos(millis as u128 * 1_000_000);
139 }
140
141 pub fn advance_nanos(&self, nanos: u128) {
143 self.set_nanos(self.now_nanos() + nanos);
144 }
145
146 pub fn advance_micros(&self, micros: u64) {
148 self.advance_nanos(micros as u128 * 1_000);
149 }
150
151 pub fn advance_millis(&self, millis: u64) {
153 self.advance_nanos(millis as u128 * 1_000_000);
154 }
155
156 pub fn advance_secs(&self, secs: u64) {
158 self.advance_nanos(secs as u128 * 1_000_000_000);
159 }
160
161 pub fn advance_minutes(&self, minutes: u64) {
163 self.advance_secs(minutes * 60);
164 }
165
166 pub fn advance_hours(&self, hours: u64) {
168 self.advance_secs(hours * 3600);
169 }
170
171 pub fn advance_days(&self, days: u64) {
173 self.advance_secs(days * 86400);
174 }
175}
176
177#[derive(Clone)]
178enum InstantInner {
179 Real(time::Instant),
180 Mock {
181 captured_nanos: u128,
182 clock: MockClock,
183 },
184}
185
186#[derive(Clone)]
187pub struct Instant {
188 inner: InstantInner,
189}
190
191impl Instant {
192 #[inline]
193 pub fn elapsed(&self) -> Duration {
194 match &self.inner {
195 InstantInner::Real(instant) => instant.elapsed(),
196 InstantInner::Mock {
197 captured_nanos,
198 clock,
199 } => {
200 let now = clock.now_nanos();
201 let elapsed_nanos = now.saturating_sub(*captured_nanos);
202 Duration::from_nanos(elapsed_nanos as u64)
203 }
204 }
205 }
206
207 #[inline]
208 pub fn duration_since(&self, earlier: Instant) -> Duration {
209 match (&self.inner, &earlier.inner) {
210 (InstantInner::Real(this), InstantInner::Real(other)) => this.duration_since(*other),
211 (
212 InstantInner::Mock {
213 captured_nanos: this_nanos,
214 ..
215 },
216 InstantInner::Mock {
217 captured_nanos: other_nanos,
218 ..
219 },
220 ) => {
221 let elapsed = this_nanos.saturating_sub(*other_nanos);
222 Duration::from_nanos(elapsed as u64)
223 }
224 _ => panic!("Cannot compare instants from different clock types"),
225 }
226 }
227}
228
229impl fmt::Debug for Instant {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 match &self.inner {
232 InstantInner::Real(instant) => f.debug_tuple("Instant::Real").field(instant).finish(),
233 InstantInner::Mock {
234 captured_nanos,
235 ..
236 } => f.debug_tuple("Instant::Mock").field(captured_nanos).finish(),
237 }
238 }
239}