1use sim_kernel::{Error, Result};
2use std::sync::{
3 Arc,
4 atomic::{AtomicU64, Ordering},
5};
6#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
8pub struct WallTimestamp(u64);
9impl WallTimestamp {
10 pub const fn from_unix_millis(value: u64) -> Self {
12 Self(value)
13 }
14 pub const fn unix_millis(self) -> u64 {
16 self.0
17 }
18}
19#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
21pub struct MonotonicTimestamp(u64);
22impl MonotonicTimestamp {
23 pub const fn from_nanos(value: u64) -> Self {
25 Self(value)
26 }
27 pub const fn nanos(self) -> u64 {
29 self.0
30 }
31}
32pub trait WallClock: Send + Sync {
34 fn now(&self) -> Result<WallTimestamp>;
36 fn now_ms(&self) -> Result<u64> {
38 self.now().map(WallTimestamp::unix_millis)
39 }
40}
41pub trait MonotonicClock: Send + Sync {
43 fn now_monotonic(&self) -> Result<MonotonicTimestamp>;
45}
46pub trait Timer: Send + Sync {
48 fn wait_until(&self, deadline: MonotonicTimestamp) -> Result<()>;
50}
51#[derive(Clone)]
53pub struct PlatformTime {
54 pub wall: Arc<dyn WallClock>,
56 pub monotonic: Arc<dyn MonotonicClock>,
58 pub timer: Arc<dyn Timer>,
60}
61#[derive(Clone, Copy, Debug, Default)]
63pub struct SystemWallClock;
64impl WallClock for SystemWallClock {
65 fn now(&self) -> Result<WallTimestamp> {
66 Ok(WallTimestamp::from_unix_millis(0))
67 }
68}
69#[derive(Debug)]
71pub struct DeterministicTime {
72 next_wall_ms: AtomicU64,
73 now_ns: AtomicU64,
74 wall_step_ns: u64,
75}
76impl DeterministicTime {
77 pub const fn new(wall_epoch_ms: u64, wall_step_ms: u64) -> Self {
79 Self {
80 next_wall_ms: AtomicU64::new(wall_epoch_ms),
81 now_ns: AtomicU64::new(0),
82 wall_step_ns: wall_step_ms.saturating_mul(1_000_000),
83 }
84 }
85}
86impl Clone for DeterministicTime {
87 fn clone(&self) -> Self {
88 Self {
89 next_wall_ms: AtomicU64::new(self.next_wall_ms.load(Ordering::Acquire)),
90 now_ns: AtomicU64::new(self.now_ns.load(Ordering::Acquire)),
91 wall_step_ns: self.wall_step_ns,
92 }
93 }
94}
95impl WallClock for DeterministicTime {
96 fn now(&self) -> Result<WallTimestamp> {
97 self.next_wall_ms
98 .fetch_update(Ordering::AcqRel, Ordering::Acquire, |value| {
99 value.checked_add(self.wall_step_ns / 1_000_000)
100 })
101 .map(WallTimestamp::from_unix_millis)
102 .map_err(|_| Error::Eval("deterministic wall clock overflow".into()))
103 }
104}
105impl MonotonicClock for DeterministicTime {
106 fn now_monotonic(&self) -> Result<MonotonicTimestamp> {
107 Ok(MonotonicTimestamp::from_nanos(
108 self.now_ns.load(Ordering::Acquire),
109 ))
110 }
111}
112impl Timer for DeterministicTime {
113 fn wait_until(&self, deadline: MonotonicTimestamp) -> Result<()> {
114 self.now_ns.fetch_max(deadline.nanos(), Ordering::AcqRel);
115 Ok(())
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn deterministic_binding_preserves_wall_behavior_and_composes_timer() {
125 let time = Arc::new(DeterministicTime::new(1_000, 25));
126 let binding = PlatformTime {
127 wall: time.clone(),
128 monotonic: time.clone(),
129 timer: time,
130 };
131 assert_eq!(binding.wall.now_ms().unwrap(), 1_000);
132 assert_eq!(binding.wall.now_ms().unwrap(), 1_025);
133 binding
134 .timer
135 .wait_until(MonotonicTimestamp::from_nanos(50_000_000))
136 .unwrap();
137 assert_eq!(
138 binding.monotonic.now_monotonic().unwrap(),
139 MonotonicTimestamp::from_nanos(50_000_000)
140 );
141 }
142
143 #[test]
144 fn deterministic_wall_overflow_remains_fail_closed() {
145 let time = DeterministicTime::new(u64::MAX, 1);
146 assert!(time.now().is_err());
147 }
148}