1use cap_std::time::{Duration, Instant, SystemClock, SystemTime};
2use cap_std::{AmbientAuthority, ambient_authority};
3use std::error::Error;
4use std::fmt;
5use wasmtime::component::{HasData, ResourceTable};
6
7pub struct WasiClocks;
46
47impl HasData for WasiClocks {
48 type Data<'a> = WasiClocksCtxView<'a>;
49}
50
51pub struct WasiClocksCtx {
52 pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
53 pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,
54}
55
56impl Default for WasiClocksCtx {
57 fn default() -> Self {
58 Self {
59 wall_clock: wall_clock(),
60 monotonic_clock: monotonic_clock(),
61 }
62 }
63}
64
65pub trait WasiClocksView: Send {
66 fn clocks(&mut self) -> WasiClocksCtxView<'_>;
67}
68
69pub struct WasiClocksCtxView<'a> {
70 pub ctx: &'a mut WasiClocksCtx,
71 pub table: &'a mut ResourceTable,
72}
73
74pub trait HostWallClock: Send {
75 fn resolution(&self) -> Duration;
76 fn now(&self) -> Duration;
77}
78
79pub trait HostMonotonicClock: Send {
80 fn resolution(&self) -> u64;
81 fn now(&self) -> u64;
82}
83
84pub struct WallClock {
85 clock: cap_std::time::SystemClock,
87}
88
89impl Default for WallClock {
90 fn default() -> Self {
91 Self::new(ambient_authority())
92 }
93}
94
95impl WallClock {
96 pub fn new(ambient_authority: AmbientAuthority) -> Self {
97 Self {
98 clock: cap_std::time::SystemClock::new(ambient_authority),
99 }
100 }
101}
102
103impl HostWallClock for WallClock {
104 fn resolution(&self) -> Duration {
105 #[cfg(unix)]
106 {
107 let res = rustix::time::clock_getres(rustix::time::ClockId::Realtime);
108 Duration::new(
109 res.tv_sec.try_into().unwrap(),
110 res.tv_nsec.try_into().unwrap(),
111 )
112 }
113 #[cfg(windows)]
114 {
115 Duration::new(0, 55_000_000)
120 }
121 }
122
123 fn now(&self) -> Duration {
124 self.clock
126 .now()
127 .duration_since(SystemClock::UNIX_EPOCH)
128 .unwrap()
129 }
130}
131
132pub struct MonotonicClock {
133 clock: cap_std::time::MonotonicClock,
135
136 initial: Instant,
139}
140
141impl Default for MonotonicClock {
142 fn default() -> Self {
143 Self::new(ambient_authority())
144 }
145}
146
147impl MonotonicClock {
148 pub fn new(ambient_authority: AmbientAuthority) -> Self {
149 let clock = cap_std::time::MonotonicClock::new(ambient_authority);
150 let initial = clock.now();
151 Self { clock, initial }
152 }
153}
154
155impl HostMonotonicClock for MonotonicClock {
156 fn resolution(&self) -> u64 {
157 #[cfg(unix)]
158 {
159 let res = rustix::time::clock_getres(rustix::time::ClockId::Monotonic);
160 u64::try_from(res.tv_sec).unwrap() * 1_000_000_000 + u64::try_from(res.tv_nsec).unwrap()
161 }
162 #[cfg(windows)]
163 {
164 use windows_sys::Win32::System::Performance::QueryPerformanceFrequency;
165
166 unsafe {
167 let mut frequency = 0;
168 if QueryPerformanceFrequency(&mut frequency) == 0 {
169 panic!(
170 "QueryPerformanceFrequency failed: {}",
171 std::io::Error::last_os_error()
172 );
173 }
174 1_000_000_000 / u64::try_from(frequency).unwrap()
175 }
176 }
177 }
178
179 fn now(&self) -> u64 {
180 self.clock
183 .now()
184 .duration_since(self.initial)
185 .as_nanos()
186 .try_into()
187 .unwrap()
188 }
189}
190
191pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
192 Box::new(MonotonicClock::default())
193}
194
195pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
196 Box::new(WallClock::default())
197}
198
199pub(crate) struct Datetime {
200 pub seconds: i64,
201 pub nanoseconds: u32,
202}
203
204impl TryFrom<SystemTime> for Datetime {
205 type Error = DatetimeError;
206
207 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
208 let epoch = SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH);
209
210 if time >= epoch {
211 let duration = time.duration_since(epoch)?;
212 Ok(Self {
213 seconds: duration.as_secs().try_into()?,
214 nanoseconds: duration.subsec_nanos(),
215 })
216 } else {
217 let duration = epoch.duration_since(time)?;
218 Ok(Self {
219 seconds: -duration.as_secs().try_into()?,
220 nanoseconds: duration.subsec_nanos(),
221 })
222 }
223 }
224}
225
226#[derive(Debug)]
227pub struct DatetimeError;
228
229impl fmt::Display for DatetimeError {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 f.write_str("couldn't represent time as a WASI `Datetime`")
232 }
233}
234
235impl Error for DatetimeError {}
236
237impl From<std::time::SystemTimeError> for DatetimeError {
238 fn from(_: std::time::SystemTimeError) -> Self {
239 DatetimeError
240 }
241}
242
243impl From<std::num::TryFromIntError> for DatetimeError {
244 fn from(_: std::num::TryFromIntError) -> Self {
245 DatetimeError
246 }
247}