wasi_async_runtime/
block_on.rs

1use super::Reactor;
2
3use core::future::Future;
4use core::pin::pin;
5use core::ptr;
6use core::task::Waker;
7use core::task::{Context, Poll, RawWaker, RawWakerVTable};
8
9/// Start the event loop
10pub fn block_on<F, Fut>(f: F) -> Fut::Output
11where
12    F: FnOnce(Reactor) -> Fut,
13    Fut: Future,
14{
15    // Construct the reactor
16    let reactor = Reactor::new();
17
18    // Create the future and pin it so it can be polled
19    let fut = (f)(reactor.clone());
20    let mut fut = pin!(fut);
21
22    // Create a new context to be passed to the future.
23    let waker = noop_waker();
24    let mut cx = Context::from_waker(&waker);
25
26    // Either the future completes and we return, or some IO is happening
27    // and we wait.
28    loop {
29        match fut.as_mut().poll(&mut cx) {
30            Poll::Ready(res) => return res,
31            Poll::Pending => reactor.block_until(),
32        }
33    }
34}
35
36/// Construct a new no-op waker
37// NOTE: we can remove this once <https://github.com/rust-lang/rust/issues/98286> lands
38fn noop_waker() -> Waker {
39    const VTABLE: RawWakerVTable = RawWakerVTable::new(
40        // Cloning just returns a new no-op raw waker
41        |_| RAW,
42        // `wake` does nothing
43        |_| {},
44        // `wake_by_ref` does nothing
45        |_| {},
46        // Dropping does nothing as we don't allocate anything
47        |_| {},
48    );
49    const RAW: RawWaker = RawWaker::new(ptr::null(), &VTABLE);
50
51    // SAFETY: all fields are no-ops, so this is safe
52    unsafe { Waker::from_raw(RAW) }
53}