wasmtime_wasi/p2/host/
clocks.rs1use crate::p2::bindings::{
2 clocks::monotonic_clock::{self, Duration as WasiDuration, Instant},
3 clocks::wall_clock::{self, Datetime},
4};
5use crate::p2::{DynPollable, IoView, WasiImpl, WasiView};
6use cap_std::time::SystemTime;
7use std::time::Duration;
8use wasmtime::component::Resource;
9use wasmtime_wasi_io::poll::{subscribe, Pollable};
10
11impl TryFrom<SystemTime> for Datetime {
12 type Error = anyhow::Error;
13
14 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
15 let duration =
16 time.duration_since(SystemTime::from_std(std::time::SystemTime::UNIX_EPOCH))?;
17
18 Ok(Datetime {
19 seconds: duration.as_secs(),
20 nanoseconds: duration.subsec_nanos(),
21 })
22 }
23}
24
25impl<T> wall_clock::Host for WasiImpl<T>
26where
27 T: WasiView,
28{
29 fn now(&mut self) -> anyhow::Result<Datetime> {
30 let now = self.ctx().wall_clock.now();
31 Ok(Datetime {
32 seconds: now.as_secs(),
33 nanoseconds: now.subsec_nanos(),
34 })
35 }
36
37 fn resolution(&mut self) -> anyhow::Result<Datetime> {
38 let res = self.ctx().wall_clock.resolution();
39 Ok(Datetime {
40 seconds: res.as_secs(),
41 nanoseconds: res.subsec_nanos(),
42 })
43 }
44}
45
46fn subscribe_to_duration(
47 table: &mut wasmtime::component::ResourceTable,
48 duration: tokio::time::Duration,
49) -> anyhow::Result<Resource<DynPollable>> {
50 let sleep = if duration.is_zero() {
51 table.push(Deadline::Past)?
52 } else if let Some(deadline) = tokio::time::Instant::now().checked_add(duration) {
53 table.push(Deadline::Instant(deadline))?
57 } else {
58 table.push(Deadline::Never)?
61 };
62 subscribe(table, sleep)
63}
64
65impl<T> monotonic_clock::Host for WasiImpl<T>
66where
67 T: WasiView,
68{
69 fn now(&mut self) -> anyhow::Result<Instant> {
70 Ok(self.ctx().monotonic_clock.now())
71 }
72
73 fn resolution(&mut self) -> anyhow::Result<Instant> {
74 Ok(self.ctx().monotonic_clock.resolution())
75 }
76
77 fn subscribe_instant(&mut self, when: Instant) -> anyhow::Result<Resource<DynPollable>> {
78 let clock_now = self.ctx().monotonic_clock.now();
79 let duration = if when > clock_now {
80 Duration::from_nanos(when - clock_now)
81 } else {
82 Duration::from_nanos(0)
83 };
84 subscribe_to_duration(&mut self.table(), duration)
85 }
86
87 fn subscribe_duration(
88 &mut self,
89 duration: WasiDuration,
90 ) -> anyhow::Result<Resource<DynPollable>> {
91 subscribe_to_duration(&mut self.table(), Duration::from_nanos(duration))
92 }
93}
94
95enum Deadline {
96 Past,
97 Instant(tokio::time::Instant),
98 Never,
99}
100
101#[async_trait::async_trait]
102impl Pollable for Deadline {
103 async fn ready(&mut self) {
104 match self {
105 Deadline::Past => {}
106 Deadline::Instant(instant) => tokio::time::sleep_until(*instant).await,
107 Deadline::Never => std::future::pending().await,
108 }
109 }
110}