wasmtime_wasi/
clocks.rs

1use cap_std::time::{Duration, Instant, SystemClock};
2use cap_std::{AmbientAuthority, ambient_authority};
3use cap_time_ext::{MonotonicClockExt as _, SystemClockExt as _};
4use wasmtime::component::{HasData, ResourceTable};
5
6pub(crate) struct WasiClocks;
7
8impl HasData for WasiClocks {
9    type Data<'a> = WasiClocksCtxView<'a>;
10}
11
12pub struct WasiClocksCtx {
13    pub wall_clock: Box<dyn HostWallClock + Send>,
14    pub monotonic_clock: Box<dyn HostMonotonicClock + Send>,
15}
16
17impl Default for WasiClocksCtx {
18    fn default() -> Self {
19        Self {
20            wall_clock: wall_clock(),
21            monotonic_clock: monotonic_clock(),
22        }
23    }
24}
25
26pub trait WasiClocksView: Send {
27    fn clocks(&mut self) -> WasiClocksCtxView<'_>;
28}
29
30pub struct WasiClocksCtxView<'a> {
31    pub ctx: &'a mut WasiClocksCtx,
32    pub table: &'a mut ResourceTable,
33}
34
35pub trait HostWallClock: Send {
36    fn resolution(&self) -> Duration;
37    fn now(&self) -> Duration;
38}
39
40pub trait HostMonotonicClock: Send {
41    fn resolution(&self) -> u64;
42    fn now(&self) -> u64;
43}
44
45pub struct WallClock {
46    /// The underlying system clock.
47    clock: cap_std::time::SystemClock,
48}
49
50impl Default for WallClock {
51    fn default() -> Self {
52        Self::new(ambient_authority())
53    }
54}
55
56impl WallClock {
57    pub fn new(ambient_authority: AmbientAuthority) -> Self {
58        Self {
59            clock: cap_std::time::SystemClock::new(ambient_authority),
60        }
61    }
62}
63
64impl HostWallClock for WallClock {
65    fn resolution(&self) -> Duration {
66        self.clock.resolution()
67    }
68
69    fn now(&self) -> Duration {
70        // WASI defines wall clocks to return "Unix time".
71        self.clock
72            .now()
73            .duration_since(SystemClock::UNIX_EPOCH)
74            .unwrap()
75    }
76}
77
78pub struct MonotonicClock {
79    /// The underlying system clock.
80    clock: cap_std::time::MonotonicClock,
81
82    /// The `Instant` this clock was created. All returned times are
83    /// durations since that time.
84    initial: Instant,
85}
86
87impl Default for MonotonicClock {
88    fn default() -> Self {
89        Self::new(ambient_authority())
90    }
91}
92
93impl MonotonicClock {
94    pub fn new(ambient_authority: AmbientAuthority) -> Self {
95        let clock = cap_std::time::MonotonicClock::new(ambient_authority);
96        let initial = clock.now();
97        Self { clock, initial }
98    }
99}
100
101impl HostMonotonicClock for MonotonicClock {
102    fn resolution(&self) -> u64 {
103        self.clock.resolution().as_nanos().try_into().unwrap()
104    }
105
106    fn now(&self) -> u64 {
107        // Unwrap here and in `resolution` above; a `u64` is wide enough to
108        // hold over 584 years of nanoseconds.
109        self.clock
110            .now()
111            .duration_since(self.initial)
112            .as_nanos()
113            .try_into()
114            .unwrap()
115    }
116}
117
118pub fn monotonic_clock() -> Box<dyn HostMonotonicClock + Send> {
119    Box::new(MonotonicClock::default())
120}
121
122pub fn wall_clock() -> Box<dyn HostWallClock + Send> {
123    Box::new(WallClock::default())
124}