aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util/sync_executor.rs
blob: b7512c2d3596a9a5d3f90a358aa695c55edfafcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//! Minimal synchronous future executor used as a drop-in for the `tokio::runtime::Runtime::new()`
//! + `block_on` sync bridges scattered across the codebase (repository / installer / downloader).
//!
//! Those bridges drive `async fn`s whose `.await` points all resolve synchronously: the only async
//! I/O (reqwest in `CurlDownloader`) is performed through a blocking client, so no reactor is
//! required. Nesting `tokio` runtimes is forbidden ("Cannot start a runtime from within a runtime"),
//! which is why this no-reactor executor exists; it can be nested freely.
//!
//! TODO(phase-e): remove this module once the async bridges are either made genuinely synchronous or
//! consolidated onto a single shared runtime driven from `main`.

use std::future::Future;
use std::task::{Context, Poll};

/// Polls `fut` to completion on the current thread without any tokio runtime.
///
/// Relies on the invariant that no awaited future parks on a reactor (it would otherwise spin).
pub fn block_on<F: Future>(fut: F) -> F::Output {
    let mut fut = std::pin::pin!(fut);
    let waker = std::task::Waker::noop();
    let mut cx = Context::from_waker(waker);
    loop {
        if let Poll::Ready(value) = fut.as_mut().poll(&mut cx) {
            return value;
        }
        std::hint::spin_loop();
    }
}