Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wasi-io/src/poll.rs
1692 views
1
use alloc::boxed::Box;
2
use anyhow::Result;
3
use core::any::Any;
4
use core::future::Future;
5
use core::pin::Pin;
6
use wasmtime::component::{Resource, ResourceTable};
7
8
pub type DynFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
9
pub type MakeFuture = for<'a> fn(&'a mut dyn Any) -> DynFuture<'a>;
10
11
/// The host representation of the `wasi:io/poll.pollable` resource.
12
///
13
/// A pollable is not the same thing as a Rust Future: the same pollable may be used to
14
/// repeatedly check for readiness of a given condition, e.g. if a stream is readable
15
/// or writable. So, rather than containing a Future, which can only become Ready once, a
16
/// `DynPollable` contains a way to create a Future in each call to `poll`.
17
pub struct DynPollable {
18
pub(crate) index: u32,
19
pub(crate) make_future: MakeFuture,
20
pub(crate) remove_index_on_delete: Option<fn(&mut ResourceTable, u32) -> Result<()>>,
21
}
22
23
/// The trait used to implement [`DynPollable`] to create a `pollable`
24
/// resource in `wasi:io/poll`.
25
///
26
/// This trait is the internal implementation detail of any pollable resource in
27
/// this crate's implementation of WASI. The `ready` function is an `async fn`
28
/// which resolves when the implementation is ready. Using native `async` Rust
29
/// enables this type's readiness to compose with other types' readiness
30
/// throughout the WASI implementation.
31
///
32
/// This trait is used in conjunction with [`subscribe`] to create a `pollable`
33
/// resource.
34
///
35
/// # Example
36
///
37
/// This is a simple example of creating a `Pollable` resource from a few
38
/// parameters.
39
///
40
/// ```
41
/// # // stub out so we don't need a dep to build the doctests:
42
/// # mod tokio { pub mod time { pub use std::time::{Duration, Instant}; pub async fn sleep_until(_: Instant) {} } }
43
/// use tokio::time::{self, Duration, Instant};
44
/// use wasmtime_wasi_io::{IoView, poll::{Pollable, subscribe, DynPollable}, async_trait};
45
/// use wasmtime::component::Resource;
46
/// use wasmtime::Result;
47
///
48
/// fn sleep(cx: &mut dyn IoView, dur: Duration) -> Result<Resource<DynPollable>> {
49
/// let end = Instant::now() + dur;
50
/// let sleep = MySleep { end };
51
/// let sleep_resource = cx.table().push(sleep)?;
52
/// subscribe(cx.table(), sleep_resource)
53
/// }
54
///
55
/// struct MySleep {
56
/// end: Instant,
57
/// }
58
///
59
/// #[async_trait]
60
/// impl Pollable for MySleep {
61
/// async fn ready(&mut self) {
62
/// tokio::time::sleep_until(self.end).await;
63
/// }
64
/// }
65
/// ```
66
#[async_trait::async_trait]
67
pub trait Pollable: Send + 'static {
68
/// An asynchronous function which resolves when this object's readiness
69
/// operation is ready.
70
///
71
/// This function is invoked as part of `poll` in `wasi:io/poll`. The
72
/// meaning of when this function Returns depends on what object this
73
/// [`Pollable`] is attached to. When the returned future resolves then the
74
/// corresponding call to `wasi:io/poll` will return.
75
///
76
/// Note that this method does not return an error. Returning an error
77
/// should be done through accessors on the object that this `pollable` is
78
/// connected to. The call to `wasi:io/poll` itself does not return errors,
79
/// only a list of ready objects.
80
async fn ready(&mut self);
81
}
82
83
/// Creates a `wasi:io/poll/pollable` resource which is subscribed to the provided
84
/// `resource`.
85
///
86
/// If `resource` is an owned resource then it will be deleted when the returned
87
/// resource is deleted. Otherwise the returned resource is considered a "child"
88
/// of the given `resource` which means that the given resource cannot be
89
/// deleted while the `pollable` is still alive.
90
pub fn subscribe<T>(
91
table: &mut ResourceTable,
92
resource: Resource<T>,
93
) -> Result<Resource<DynPollable>>
94
where
95
T: Pollable,
96
{
97
fn make_future<'a, T>(stream: &'a mut dyn Any) -> DynFuture<'a>
98
where
99
T: Pollable,
100
{
101
stream.downcast_mut::<T>().unwrap().ready()
102
}
103
104
let pollable = DynPollable {
105
index: resource.rep(),
106
remove_index_on_delete: if resource.owned() {
107
Some(|table, idx| {
108
let resource = Resource::<T>::new_own(idx);
109
table.delete(resource)?;
110
Ok(())
111
})
112
} else {
113
None
114
},
115
make_future: make_future::<T>,
116
};
117
118
Ok(table.push_child(pollable, &resource)?)
119
}
120
121