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