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 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 self.clock
72 .now()
73 .duration_since(SystemClock::UNIX_EPOCH)
74 .unwrap()
75 }
76}
77
78pub struct MonotonicClock {
79 clock: cap_std::time::MonotonicClock,
81
82 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 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}