Skip to content

Commit ee562ec

Browse files
committed
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
1 parent 718aa74 commit ee562ec

File tree

2 files changed

+29
-7
lines changed

2 files changed

+29
-7
lines changed

src/runtime/block_on.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ use std::task::{Context, Poll, Waker};
77
/// Start the event loop. Blocks until the future
88
pub fn block_on<F>(fut: F) -> F::Output
99
where
10-
F: Future + 'static,
11-
F::Output: 'static,
10+
F: Future,
1211
{
1312
// Construct the reactor
1413
let reactor = Reactor::new();
@@ -19,7 +18,11 @@ where
1918
}
2019

2120
// Spawn the task onto the reactor.
22-
let root_task = reactor.spawn(fut);
21+
// Safety: The execution loop below, concluding with pulling the Ready out
22+
// of the root_task, ensures that it does not outlive the Future or its
23+
// output.
24+
#[allow(unsafe_code)]
25+
let root_task = unsafe { reactor.spawn_unchecked(fut) };
2326

2427
loop {
2528
match reactor.pop_ready_list() {

src/runtime/reactor.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,11 +258,17 @@ impl Reactor {
258258
ready
259259
}
260260

261-
/// Spawn a `Task` on the `Reactor`.
262-
pub fn spawn<F, T>(&self, fut: F) -> Task<T>
261+
/// We need an unchecked spawn for implementing `block_on`, where the
262+
/// implementation does not expose the resulting Task and does not return
263+
/// until all tasks have finished execution.
264+
///
265+
/// # Safety
266+
/// Caller must ensure that the Task<T> does not outlive the Future F or
267+
/// F::Output T.
268+
#[allow(unsafe_code)]
269+
pub(crate) unsafe fn spawn_unchecked<F, T>(&self, fut: F) -> Task<T>
263270
where
264-
F: Future<Output = T> + 'static,
265-
T: 'static,
271+
F: Future<Output = T>,
266272
{
267273
let this = self.clone();
268274
let schedule = move |runnable| this.inner.ready_list.lock().unwrap().push_back(runnable);
@@ -278,6 +284,19 @@ impl Reactor {
278284
task
279285
}
280286

287+
/// Spawn a `Task` on the `Reactor`.
288+
pub fn spawn<F, T>(&self, fut: F) -> Task<T>
289+
where
290+
F: Future<Output = T> + 'static,
291+
T: 'static,
292+
{
293+
// Safety: 'static constraints satisfy the lifetime requirements
294+
#[allow(unsafe_code)]
295+
unsafe {
296+
self.spawn_unchecked(fut)
297+
}
298+
}
299+
281300
pub(super) fn pop_ready_list(&self) -> Option<Runnable> {
282301
self.inner.ready_list.lock().unwrap().pop_front()
283302
}

0 commit comments

Comments
 (0)