1use cap_std::time::{Duration, Instant, SystemClock, SystemTime};
2use cap_std::{AmbientAuthority, ambient_authority};
3use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
4use wasmtime::component::{HasData, ResourceTable};
5
6pub struct WasiClocks;
45
46impl HasData for WasiClocks {
47 type Data<'a> = WasiClocksCtxView<'a>;
48}
49
50pub struct WasiClocksCtx {
51 pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
52 pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,
53}
54
55impl Default for WasiClocksCtx {
56 fn default() -> Self {
57 Self {
58 wall_clock: wall_clock(),
59 monotonic_clock: monotonic_clock(),
60 }
61 }
62}
63
64pub trait WasiClocksView: Send {
65 fn clocks(&mut self) -> WasiClocksCtxView<'_>;
66}
67
68pub struct WasiClocksCtxView<'a> {
69 pub ctx: &'a mut WasiClocksCtx,
70 pub table: &'a mut ResourceTable,
71}
72
73pub trait HostWallClock: Send {
74 fn resolution(&self) -> Duration;
75 fn now(&self) -> Duration;
76}
77
78pub trait HostMonotonicClock: Send {
79 fn resolution(&self) -> u64;
80 fn now(&self) -> u64;
81}
82
83pub struct WallClock {
84 clock: cap_std::time::SystemClock,
86}
87
88impl Default for WallClock {
89 fn default() -> Self {
90 Self::new(ambient_authority())
91 }
92}
93
94impl WallClock {
95 pub fn new(ambient_authority: AmbientAuthority) -> Self {
96 Self {
97 clock: cap_std::time::SystemClock::new(ambient_authority),
98 }
99 }
100}
101
102impl HostWallClock for WallClock {
103 fn resolution(&self) -> Duration {
104 self.clock.resolution()
105 }
106
107 fn now(&self) -> Duration {
108 self.clock
110 .now()
111 .duration_since(SystemClock::UNIX_EPOCH)
112 .unwrap()
113 }
114}
115
116pub struct MonotonicClock {
117 clock: cap_std::time::MonotonicClock,
119
120 initial: Instant,
123}
124
125impl Default for MonotonicClock {
126 fn default() -> Self {
127 Self::new(ambient_authority())
128 }
129}
130
131impl MonotonicClock {
132 pub fn new(ambient_authority: AmbientAuthority) -> Self {
133 let clock = cap_std::time::MonotonicClock::new(ambient_authority);
134 let initial = clock.now();
135 Self { clock, initial }
136 }
137}
138
139impl HostMonotonicClock for MonotonicClock {
140 fn resolution(&self) -> u64 {
141 self.clock.resolution().as_nanos().try_into().unwrap()
142 }
143
144 fn now(&self) -> u64 {
145 self.clock
148 .now()
149 .duration_since(self.initial)
150 .as_nanos()
151 .try_into()
152 .unwrap()
153 }
154}
155
156pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
157 Box::new(MonotonicClock::default())
158}
159
160pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
161 Box::new(WallClock::default())
162}
163
164pub(crate) struct Datetime {
165 pub seconds: u64,
166 pub nanoseconds: u32,
167}
168
169impl TryFrom<SystemTime> for Datetime {
170 type Error = wasmtime::Error;
171
172 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
173 let duration =
174 time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?;
175
176 Ok(Self {
177 seconds: duration.as_secs(),
178 nanoseconds: duration.subsec_nanos(),
179 })
180 }
181}