aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util/sync_executor.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/src/util/sync_executor.rs')
-rw-r--r--crates/shirabe/src/util/sync_executor.rs28
1 files changed, 28 insertions, 0 deletions
diff --git a/crates/shirabe/src/util/sync_executor.rs b/crates/shirabe/src/util/sync_executor.rs
new file mode 100644
index 0000000..b7512c2
--- /dev/null
+++ b/crates/shirabe/src/util/sync_executor.rs
@@ -0,0 +1,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();
+ }
+}