prov_graph/exec.rs
1//! A dependency-free executor for backends whose futures are already ready.
2//!
3//! [`crate::fs::ReadStorage`] is async so genuinely async backends fit, but the
4//! common native case — [`crate::fs::StdFs`] — produces futures that complete
5//! on the first poll. [`block_on`] drives such a future without pulling in a
6//! runtime: a no-op waker and a poll loop. It works for any future that makes
7//! progress when polled (it busy-polls; it is *not* a fair scheduler), which
8//! makes it suitable for CLIs and tests, not for I/O multiplexing.
9
10use std::future::Future;
11use std::pin::pin;
12use std::task::{Context, Poll, Waker};
13
14/// Drive `future` to completion on the current thread by polling in a loop
15/// with a no-op waker.
16pub fn block_on<F: Future>(future: F) -> F::Output {
17 let mut future = pin!(future);
18 let waker = Waker::noop();
19 let mut cx = Context::from_waker(waker);
20 loop {
21 match future.as_mut().poll(&mut cx) {
22 Poll::Ready(out) => return out,
23 Poll::Pending => std::hint::spin_loop(),
24 }
25 }
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31
32 #[test]
33 fn drives_a_ready_future() {
34 assert_eq!(block_on(async { 7 }), 7);
35 }
36
37 #[test]
38 fn drives_chained_storage_futures() {
39 use crate::fs::{ReadStorage, StdFs};
40 let exists = block_on(async {
41 StdFs
42 .try_exists(std::path::Path::new("/definitely/not/here"))
43 .await
44 });
45 assert!(!exists.unwrap());
46 }
47}