exec.rsannotatedexec.rssource38 lines · 1.4 KB · raw
1//! Driving a future that never has to wait, on the spot.
2//!
3//! The native adapters block inside their `async fn`s (a file write, a blocking HTTP call), and the
4//! in-memory adapter does no waiting at all, so every future they make is `Ready` on its first poll.
5//! This runs such a future without an executor. It does NOT wait: a future that is `Pending` is a
6//! bug in the adapter (it would have needed a real executor), and this panics rather than spin.
7//! There is no thread, no clock and no I/O here, so it builds for a Worker; it is not what a Worker
8//! would use to run its own futures.
9
10use std::future::Future;
11use std::pin::pin;
12use std::task::{Context, Poll, Waker};
13
14/// 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}
23
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}