reifydb_runtime/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
157#[derive(Clone)]
158enum InstantInner {
159 Real(time::Instant),
160 Mock {
161 captured_nanos: u128,
162 clock: MockClock,
163 },
164}
165
166#[derive(Clone)]
167pub struct Instant {
168 inner: InstantInner,
169}
170
171impl Instant {
172 #[inline]
173 pub fn elapsed(&self) -> Duration {
174 match &self.inner {
175 InstantInner::Real(instant) => instant.elapsed(),
176 InstantInner::Mock {
177 captured_nanos,
178 clock,
179 } => {
180 let now = clock.now_nanos();
181 let elapsed_nanos = now.saturating_sub(*captured_nanos);
182 Duration::from_nanos(elapsed_nanos as u64)
183 }
184 }
185 }
186
187 #[inline]
188 pub fn duration_since(&self, earlier: Instant) -> Duration {
189 match (&self.inner, &earlier.inner) {
190 (InstantInner::Real(this), InstantInner::Real(other)) => this.duration_since(*other),
191 (
192 InstantInner::Mock {
193 captured_nanos: this_nanos,
194 ..
195 },
196 InstantInner::Mock {
197 captured_nanos: other_nanos,
198 ..
199 },
200 ) => {
201 let elapsed = this_nanos.saturating_sub(*other_nanos);
202 Duration::from_nanos(elapsed as u64)
203 }
204 _ => panic!("Cannot compare instants from different clock types"),
205 }
206 }
207}
208
209impl fmt::Debug for Instant {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 match &self.inner {
212 InstantInner::Real(instant) => f.debug_tuple("Instant::Real").field(instant).finish(),
213 InstantInner::Mock {
214 captured_nanos,
215 ..
216 } => f.debug_tuple("Instant::Mock").field(captured_nanos).finish(),
217 }
218 }
219}