use alloc::boxed::Box;1use anyhow::Result;2use core::any::Any;3use core::future::Future;4use core::pin::Pin;5use wasmtime::component::{Resource, ResourceTable};67pub type DynFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;8pub type MakeFuture = for<'a> fn(&'a mut dyn Any) -> DynFuture<'a>;910/// The host representation of the `wasi:io/poll.pollable` resource.11///12/// A pollable is not the same thing as a Rust Future: the same pollable may be used to13/// repeatedly check for readiness of a given condition, e.g. if a stream is readable14/// or writable. So, rather than containing a Future, which can only become Ready once, a15/// `DynPollable` contains a way to create a Future in each call to `poll`.16pub struct DynPollable {17pub(crate) index: u32,18pub(crate) make_future: MakeFuture,19pub(crate) remove_index_on_delete: Option<fn(&mut ResourceTable, u32) -> Result<()>>,20}2122/// The trait used to implement [`DynPollable`] to create a `pollable`23/// resource in `wasi:io/poll`.24///25/// This trait is the internal implementation detail of any pollable resource in26/// this crate's implementation of WASI. The `ready` function is an `async fn`27/// which resolves when the implementation is ready. Using native `async` Rust28/// enables this type's readiness to compose with other types' readiness29/// throughout the WASI implementation.30///31/// This trait is used in conjunction with [`subscribe`] to create a `pollable`32/// resource.33///34/// # Example35///36/// This is a simple example of creating a `Pollable` resource from a few37/// parameters.38///39/// ```40/// # // stub out so we don't need a dep to build the doctests:41/// # mod tokio { pub mod time { pub use std::time::{Duration, Instant}; pub async fn sleep_until(_: Instant) {} } }42/// use tokio::time::{self, Duration, Instant};43/// use wasmtime_wasi_io::{IoView, poll::{Pollable, subscribe, DynPollable}, async_trait};44/// use wasmtime::component::Resource;45/// use wasmtime::Result;46///47/// fn sleep(cx: &mut dyn IoView, dur: Duration) -> Result<Resource<DynPollable>> {48/// let end = Instant::now() + dur;49/// let sleep = MySleep { end };50/// let sleep_resource = cx.table().push(sleep)?;51/// subscribe(cx.table(), sleep_resource)52/// }53///54/// struct MySleep {55/// end: Instant,56/// }57///58/// #[async_trait]59/// impl Pollable for MySleep {60/// async fn ready(&mut self) {61/// tokio::time::sleep_until(self.end).await;62/// }63/// }64/// ```65#[async_trait::async_trait]66pub trait Pollable: Send + 'static {67/// An asynchronous function which resolves when this object's readiness68/// operation is ready.69///70/// This function is invoked as part of `poll` in `wasi:io/poll`. The71/// meaning of when this function Returns depends on what object this72/// [`Pollable`] is attached to. When the returned future resolves then the73/// corresponding call to `wasi:io/poll` will return.74///75/// Note that this method does not return an error. Returning an error76/// should be done through accessors on the object that this `pollable` is77/// connected to. The call to `wasi:io/poll` itself does not return errors,78/// only a list of ready objects.79async fn ready(&mut self);80}8182/// Creates a `wasi:io/poll/pollable` resource which is subscribed to the provided83/// `resource`.84///85/// If `resource` is an owned resource then it will be deleted when the returned86/// resource is deleted. Otherwise the returned resource is considered a "child"87/// of the given `resource` which means that the given resource cannot be88/// deleted while the `pollable` is still alive.89pub fn subscribe<T>(90table: &mut ResourceTable,91resource: Resource<T>,92) -> Result<Resource<DynPollable>>93where94T: Pollable,95{96fn make_future<'a, T>(stream: &'a mut dyn Any) -> DynFuture<'a>97where98T: Pollable,99{100stream.downcast_mut::<T>().unwrap().ready()101}102103let pollable = DynPollable {104index: resource.rep(),105remove_index_on_delete: if resource.owned() {106Some(|table, idx| {107let resource = Resource::<T>::new_own(idx);108table.delete(resource)?;109Ok(())110})111} else {112None113},114make_future: make_future::<T>,115};116117Ok(table.push_child(pollable, &resource)?)118}119120121