exec.rsannotatedexec.rssource38 lines · 1.4 KB · raw

Driving a future that never has to wait, on the spot.

The native adapters block inside their async fns (a file write, a blocking HTTP call), and the in-memory adapter does no waiting at all, so every future they make is Ready on its first poll. This runs such a future without an executor. It does NOT wait: a future that is Pending is a bug in the adapter (it would have needed a real executor), and this panics rather than spin. There is no thread, no clock and no I/O here, so it builds for a Worker; it is not what a Worker would use to run its own futures.

10use std::future::Future;
11use std::pin::pin;
12use std::task::{Context, Poll, Waker};

Runs future to completion, panicking if it ever returns Pending.

15pub fn run_ready<F: Future>(future: F) -> F::Output {
16    let mut future = pin!(future);
17    let mut cx = Context::from_waker(Waker::noop());
18    match future.as_mut().poll(&mut cx) {
19        Poll::Ready(v) => v,
20        Poll::Pending => panic!("run_ready: a future that needed to wait was given to an executor that cannot"),
21    }
22}
24#[cfg(test)]
25mod tests {
26    use super::*;
27
28    #[test]
29    fn it_runs_a_future_that_is_ready() {
30        assert_eq!(run_ready(async { 1 + 2 }), 3);
31    }
32
33    #[test]
34    #[should_panic(expected = "needed to wait")]
35    fn it_refuses_a_future_that_must_wait() {
36        run_ready(std::future::pending::<()>());
37    }
38}