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<crate::clocks::Datetime> for Datetime {
13 type Error = crate::clocks::DatetimeError;
14
15 fn try_from(
16 crate::clocks::Datetime {
17 seconds,
18 nanoseconds,
19 }: crate::clocks::Datetime,
20 ) -> Result<Self, Self::Error> {
21 Ok(Self {
22 seconds: seconds.try_into()?,
23 nanoseconds,
24 })
25 }
26}
27
28impl TryFrom<Datetime> for crate::clocks::Datetime {
29 type Error = crate::clocks::DatetimeError;
30
31 fn try_from(
32 Datetime {
33 seconds,
34 nanoseconds,
35 }: Datetime,
36 ) -> Result<Self, Self::Error> {
37 Ok(Self {
38 seconds: seconds.try_into()?,
39 nanoseconds,
40 })
41 }
42}
43
44impl TryFrom<SystemTime> for Datetime {
45 type Error = crate::clocks::DatetimeError;
46
47 fn try_from(time: SystemTime) -> Result<Self, Self::Error> {
48 let time = crate::clocks::Datetime::try_from(time)?;
49 time.try_into()
50 }
51}
52
53impl wall_clock::Host for WasiClocksCtxView<'_> {
54 fn now(&mut self) -> wasmtime::Result<Datetime> {
55 let now = self.ctx.wall_clock.now();
56 Ok(Datetime {
57 seconds: now.as_secs(),
58 nanoseconds: now.subsec_nanos(),
59 })
60 }
61
62 fn resolution(&mut self) -> wasmtime::Result<Datetime> {
63 let res = self.ctx.wall_clock.resolution();
64 Ok(Datetime {
65 seconds: res.as_secs(),
66 nanoseconds: res.subsec_nanos(),
67 })
68 }
69}
70
71fn subscribe_to_duration(
72 table: &mut wasmtime::component::ResourceTable,
73 duration: tokio::time::Duration,
74) -> wasmtime::Result<Resource<DynPollable>> {
75 let sleep = if duration.is_zero() {
76 table.push(Deadline::Past)?
77 } else if let Some(deadline) = tokio::time::Instant::now().checked_add(duration) {
78 table.push(Deadline::Instant(deadline))?
82 } else {
83 table.push(Deadline::Never)?
86 };
87 subscribe(table, sleep)
88}
89
90impl monotonic_clock::Host for WasiClocksCtxView<'_> {
91 fn now(&mut self) -> wasmtime::Result<Instant> {
92 Ok(self.ctx.monotonic_clock.now())
93 }
94
95 fn resolution(&mut self) -> wasmtime::Result<Instant> {
96 Ok(self.ctx.monotonic_clock.resolution())
97 }
98
99 fn subscribe_instant(&mut self, when: Instant) -> wasmtime::Result<Resource<DynPollable>> {
100 let clock_now = self.ctx.monotonic_clock.now();
101 let duration = if when > clock_now {
102 Duration::from_nanos(when - clock_now)
103 } else {
104 Duration::from_nanos(0)
105 };
106 subscribe_to_duration(self.table, duration)
107 }
108
109 fn subscribe_duration(
110 &mut self,
111 duration: WasiDuration,
112 ) -> wasmtime::Result<Resource<DynPollable>> {
113 subscribe_to_duration(self.table, Duration::from_nanos(duration))
114 }
115}
116
117enum Deadline {
118 Past,
119 Instant(tokio::time::Instant),
120 Never,
121}
122
123#[async_trait::async_trait]
124impl Pollable for Deadline {
125 async fn ready(&mut self) {
126 match self {
127 Deadline::Past => {}
128 Deadline::Instant(instant) => tokio::time::sleep_until(*instant).await,
129 Deadline::Never => std::future::pending().await,
130 }
131 }
132}