From ee562ec2e5c52549f15755f0e200f7907b6f7c84 Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Wed, 12 Nov 2025 09:55:22 -0800
Subject: [PATCH 1/2] Remove 'static constraint from block_on
Factor out `spawn` into an unsafe helper `spawn_unchecked` where
`block_on` can allow a non-static future and output to execute because
dataflow ensures the Task does not outlive the future.
Fixes #107
---
src/runtime/block_on.rs | 9 ++++++---
src/runtime/reactor.rs | 27 +++++++++++++++++++++++----
2 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/src/runtime/block_on.rs b/src/runtime/block_on.rs
index 34f0dfa..c7bbd31 100644
--- a/src/runtime/block_on.rs
+++ b/src/runtime/block_on.rs
@@ -7,8 +7,7 @@ use std::task::{Context, Poll, Waker};
/// Start the event loop. Blocks until the future
pub fn block_on(fut: F) -> F::Output
where
- F: Future + 'static,
- F::Output: 'static,
+ F: Future,
{
// Construct the reactor
let reactor = Reactor::new();
@@ -19,7 +18,11 @@ where
}
// Spawn the task onto the reactor.
- let root_task = reactor.spawn(fut);
+ // Safety: The execution loop below, concluding with pulling the Ready out
+ // of the root_task, ensures that it does not outlive the Future or its
+ // output.
+ #[allow(unsafe_code)]
+ let root_task = unsafe { reactor.spawn_unchecked(fut) };
loop {
match reactor.pop_ready_list() {
diff --git a/src/runtime/reactor.rs b/src/runtime/reactor.rs
index ba78fd9..32dc073 100644
--- a/src/runtime/reactor.rs
+++ b/src/runtime/reactor.rs
@@ -258,11 +258,17 @@ impl Reactor {
ready
}
- /// Spawn a `Task` on the `Reactor`.
- pub fn spawn(&self, fut: F) -> Task
+ /// We need an unchecked spawn for implementing `block_on`, where the
+ /// implementation does not expose the resulting Task and does not return
+ /// until all tasks have finished execution.
+ ///
+ /// # Safety
+ /// Caller must ensure that the Task does not outlive the Future F or
+ /// F::Output T.
+ #[allow(unsafe_code)]
+ pub(crate) unsafe fn spawn_unchecked(&self, fut: F) -> Task
where
- F: Future