Skip to main content

reifydb_runtime/context/clock/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::fmt::Debug;
5
6#[cfg(any(reifydb_target = "host", reifydb_dst))]
7mod host;
8#[cfg(reifydb_target = "wasi")]
9mod wasi;
10#[cfg(reifydb_target = "wasm")]
11mod wasm;
12
13#[cfg(any(reifydb_target = "host", reifydb_dst))]
14pub use host::{Clock, Instant, MockClock};
15use reifydb_value::{clock::ClockNow, value::datetime::DateTime};
16#[cfg(reifydb_target = "wasi")]
17pub use wasi::{Clock, Instant, MockClock};
18#[cfg(reifydb_target = "wasm")]
19pub use wasm::{Clock, Instant, MockClock};
20
21impl ClockNow for Clock {
22	fn now(&self) -> DateTime {
23		Clock::now(self)
24	}
25}
26
27pub trait TimerWake: Debug + Send + Sync {
28	fn wake(&self);
29}
30
31#[derive(Clone, Copy, PartialEq, Eq, Debug)]
32pub struct TimerId(u64);
33
34#[cfg(test)]
35mod tests {
36	#[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
37	use std::thread;
38
39	use super::*;
40
41	#[test]
42	fn test_real_clock() {
43		let clock = Clock::Real;
44		let t1 = clock.now().to_millis();
45		// Busy work rather than a sleep; the assertion only requires the clock not to go
46		// backwards, so it holds whether or not a millisecond actually elapsed.
47		let mut sum = 0;
48		for i in 0..10000 {
49			sum += i;
50		}
51		let t2 = clock.now().to_millis();
52		assert!(t2 >= t1, "Time should not go backwards");
53		let _ = sum;
54	}
55
56	#[test]
57	fn test_mock_clock_initial() {
58		let mock = MockClock::from_millis(1000);
59		let clock = Clock::Mock(mock);
60
61		assert_eq!(clock.now().to_millis(), 1000);
62		assert_eq!(clock.now().to_micros(), 1_000_000);
63		assert_eq!(clock.now().to_nanos(), 1_000_000_000);
64	}
65
66	#[test]
67	fn test_mock_clock_set() {
68		let mock = MockClock::from_millis(0);
69		mock.set_millis(5000);
70
71		assert_eq!(mock.now().to_millis(), 5000);
72
73		mock.set_micros(6_000_000);
74		assert_eq!(mock.now().to_millis(), 6000);
75	}
76
77	#[test]
78	fn test_mock_clock_advance() {
79		let mock = MockClock::from_millis(1000);
80		let clock = Clock::Mock(mock.clone());
81
82		assert_eq!(clock.now().to_millis(), 1000);
83
84		mock.advance_millis(500);
85		assert_eq!(clock.now().to_millis(), 1500);
86
87		mock.advance_micros(500_000);
88		assert_eq!(clock.now().to_millis(), 2000);
89
90		mock.advance_nanos(500_000_000);
91		assert_eq!(clock.now().to_millis(), 2500);
92	}
93
94	#[cfg(all(reifydb_target = "host", not(reifydb_dst)))]
95	#[test]
96	fn test_mock_clock_thread_safe() {
97		let mock = MockClock::from_millis(1000);
98		let mock_clone = mock.clone();
99
100		let handle = thread::spawn(move || {
101			mock_clone.advance_millis(500);
102			mock_clone.now().to_millis()
103		});
104
105		let result = handle.join().unwrap();
106		assert_eq!(result, 1500);
107		assert_eq!(mock.now().to_millis(), 1500);
108	}
109
110	#[test]
111	fn test_nanosecond_precision() {
112		let mock = MockClock::new(1_234_567_890_123_456_789);
113		let clock = Clock::Mock(mock);
114
115		assert_eq!(clock.now().to_nanos(), 1_234_567_890_123_456_789);
116		assert_eq!(clock.now().to_micros(), 1_234_567_890_123_456);
117		assert_eq!(clock.now().to_millis(), 1_234_567_890_123);
118		assert_eq!(clock.now().to_epoch_secs(), 1_234_567_890);
119	}
120}