Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi/src/clocks.rs
3081 views
1
use cap_std::time::{Duration, Instant, SystemClock, SystemTime};
2
use cap_std::{AmbientAuthority, ambient_authority};
3
use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
4
use std::error::Error;
5
use std::fmt;
6
use wasmtime::component::{HasData, ResourceTable};
7
8
/// A helper struct which implements [`HasData`] for the `wasi:clocks` APIs.
9
///
10
/// This can be useful when directly calling `add_to_linker` functions directly,
11
/// such as [`wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker`] as
12
/// the `D` type parameter. See [`HasData`] for more information about the type
13
/// parameter's purpose.
14
///
15
/// When using this type you can skip the [`WasiClocksView`] trait, for
16
/// example.
17
///
18
/// [`wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker`]: crate::p2::bindings::clocks::monotonic_clock::add_to_linker
19
///
20
/// # Examples
21
///
22
/// ```
23
/// use wasmtime::component::{Linker, ResourceTable};
24
/// use wasmtime::{Engine, Result};
25
/// use wasmtime_wasi::clocks::*;
26
///
27
/// struct MyStoreState {
28
/// table: ResourceTable,
29
/// clocks: WasiClocksCtx,
30
/// }
31
///
32
/// fn main() -> Result<()> {
33
/// let engine = Engine::default();
34
/// let mut linker = Linker::new(&engine);
35
///
36
/// wasmtime_wasi::p2::bindings::clocks::monotonic_clock::add_to_linker::<MyStoreState, WasiClocks>(
37
/// &mut linker,
38
/// |state| WasiClocksCtxView {
39
/// table: &mut state.table,
40
/// ctx: &mut state.clocks,
41
/// },
42
/// )?;
43
/// Ok(())
44
/// }
45
/// ```
46
pub struct WasiClocks;
47
48
impl HasData for WasiClocks {
49
type Data<'a> = WasiClocksCtxView<'a>;
50
}
51
52
pub struct WasiClocksCtx {
53
pub(crate) wall_clock: Box<dyn HostWallClock + Send>,
54
pub(crate) monotonic_clock: Box<dyn HostMonotonicClock + Send>,
55
}
56
57
impl Default for WasiClocksCtx {
58
fn default() -> Self {
59
Self {
60
wall_clock: wall_clock(),
61
monotonic_clock: monotonic_clock(),
62
}
63
}
64
}
65
66
pub trait WasiClocksView: Send {
67
fn clocks(&mut self) -> WasiClocksCtxView<'_>;
68
}
69
70
pub struct WasiClocksCtxView<'a> {
71
pub ctx: &'a mut WasiClocksCtx,
72
pub table: &'a mut ResourceTable,
73
}
74
75
pub trait HostWallClock: Send {
76
fn resolution(&self) -> Duration;
77
fn now(&self) -> Duration;
78
}
79
80
pub trait HostMonotonicClock: Send {
81
fn resolution(&self) -> u64;
82
fn now(&self) -> u64;
83
}
84
85
pub struct WallClock {
86
/// The underlying system clock.
87
clock: cap_std::time::SystemClock,
88
}
89
90
impl Default for WallClock {
91
fn default() -> Self {
92
Self::new(ambient_authority())
93
}
94
}
95
96
impl WallClock {
97
pub fn new(ambient_authority: AmbientAuthority) -> Self {
98
Self {
99
clock: cap_std::time::SystemClock::new(ambient_authority),
100
}
101
}
102
}
103
104
impl HostWallClock for WallClock {
105
fn resolution(&self) -> Duration {
106
self.clock.resolution()
107
}
108
109
fn now(&self) -> Duration {
110
// WASI defines wall clocks to return "Unix time".
111
self.clock
112
.now()
113
.duration_since(SystemClock::UNIX_EPOCH)
114
.unwrap()
115
}
116
}
117
118
pub struct MonotonicClock {
119
/// The underlying system clock.
120
clock: cap_std::time::MonotonicClock,
121
122
/// The `Instant` this clock was created. All returned times are
123
/// durations since that time.
124
initial: Instant,
125
}
126
127
impl Default for MonotonicClock {
128
fn default() -> Self {
129
Self::new(ambient_authority())
130
}
131
}
132
133
impl 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
141
impl 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
// Unwrap here and in `resolution` above; a `u64` is wide enough to
148
// hold over 584 years of nanoseconds.
149
self.clock
150
.now()
151
.duration_since(self.initial)
152
.as_nanos()
153
.try_into()
154
.unwrap()
155
}
156
}
157
158
pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
159
Box::new(MonotonicClock::default())
160
}
161
162
pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
163
Box::new(WallClock::default())
164
}
165
166
pub(crate) struct Datetime {
167
pub seconds: i64,
168
pub nanoseconds: u32,
169
}
170
171
impl 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)]
194
pub struct DatetimeError;
195
196
impl 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
202
impl Error for DatetimeError {}
203
204
impl From<std::time::SystemTimeError> for DatetimeError {
205
fn from(_: std::time::SystemTimeError) -> Self {
206
DatetimeError
207
}
208
}
209
210
impl From<std::num::TryFromIntError> for DatetimeError {
211
fn from(_: std::num::TryFromIntError) -> Self {
212
DatetimeError
213
}
214
}
215
216