1use cap_std::time::{Duration, Instant, SystemClock, SystemTime};
2use cap_std::{AmbientAuthority, ambient_authority};
3use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
4use std::error::Error;
5use std::fmt;
6use wasmtime::component::{HasData, ResourceTable};
7
8pub struct WasiClocks;
47
48impl HasData for WasiClocks {
49 type Data<'a> = WasiClocksCtxView<'a>;
50}
51
52pub struct WasiClocksCtx {
53 pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
54 pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,
55}
56
57impl Default for WasiClocksCtx {
58 fn default() -> Self {
59 Self {
60 wall_clock: wall_clock(),
61 monotonic_clock: monotonic_clock(),
62 }
63 }
64}
65
66pub trait WasiClocksView: Send {
67 fn clocks(&mut self) -> WasiClocksCtxView<'_>;
68}
69
70pub struct WasiClocksCtxView<'a> {
71 pub ctx: &'a mut WasiClocksCtx,
72 pub table: &'a mut ResourceTable,
73}
74
75pub trait HostWallClock: Send {
76 fn resolution(&self) -> Duration;
77 fn now(&self) -> Duration;
78}
79
80pub trait HostMonotonicClock: Send {
81 fn resolution(&self) -> u64;
82 fn now(&self) -> u64;
83}
84
85pub struct WallClock {
86 clock: cap_std::time::SystemClock,
88}
89
90impl Default for WallClock {
91 fn default() -> Self {
92 Self::new(ambient_authority())
93 }
94}
95
96impl WallClock {
97 pub fn new(ambient_authority: AmbientAuthority) -> Self {
98 Self {
99 clock: cap_std::time::SystemClock::new(ambient_authority),
100 }
101 }
102}
103
104impl HostWallClock for WallClock {
105 fn resolution(&self) -> Duration {
106 self.clock.resolution()
107 }
108
109 fn now(&self) -> Duration {
110 self.clock
112 .now()
113 .duration_since(SystemClock::UNIX_EPOCH)
114 .unwrap()
115 }
116}
117
118pub struct MonotonicClock {
119 clock: cap_std::time::MonotonicClock,
121
122 initial: Instant,
125}
126
127impl Default for MonotonicClock {
128 fn default() -> Self {
129 Self::new(ambient_authority())
130 }
131}
132
133impl MonotonicClock {
134 pub fn new(ambient_authority: AmbientAuthority) -> Self {
135 let clock = cap_std::time::MonotonicClock::new(ambient_authority);
136 let initial = clock.now();
137 Self { clock, initial }
138 }
139}
140
141impl HostMonotonicClock for MonotonicClock {
142 fn resolution(&self) -> u64 {
143 self.clock.resolution().as_nanos().try_into().unwrap()
144 }
145
146 fn now(&self) -> u64 {
147 self.clock
150 .now()
151 .duration_since(self.initial)
152 .as_nanos()
153 .try_into()
154 .unwrap()
155 }
156}
157
158pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
159 Box::new(MonotonicClock::default())
160}
161
162pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
163 Box::new(WallClock::default())
164}
165
166pub(crate) struct Datetime {
167 pub seconds: i64,
168 pub nanoseconds: u32,
169}
170
171impl TryFrom<SystemTime> for Datetime {
172 type Error = DatetimeError;
173
174 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
175 let epoch = SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH);
176
177 if time >= epoch {
178 let duration = time.duration_since(epoch)?;
179 Ok(Self {
180 seconds: duration.as_secs().try_into()?,
181 nanoseconds: duration.subsec_nanos(),
182 })
183 } else {
184 let duration = epoch.duration_since(time)?;
185 Ok(Self {
186 seconds: -duration.as_secs().try_into()?,
187 nanoseconds: duration.subsec_nanos(),
188 })
189 }
190 }
191}
192
193#[derive(Debug)]
194pub struct DatetimeError;
195
196impl fmt::Display for DatetimeError {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.write_str("couldn't represent time as a WASI `Datetime`")
199 }
200}
201
202impl Error for DatetimeError {}
203
204impl From<std::time::SystemTimeError> for DatetimeError {
205 fn from(_: std::time::SystemTimeError) -> Self {
206 DatetimeError
207 }
208}
209
210impl From<std::num::TryFromIntError> for DatetimeError {
211 fn from(_: std::num::TryFromIntError) -> Self {
212 DatetimeError
213 }
214}