Skip to content

Commit 2b5adca

Browse files
committed
Refactor spawn_inner
1 parent 646c77a commit 2b5adca

File tree

1 file changed

+20
-15
lines changed

1 file changed

+20
-15
lines changed

src/local_executor.rs

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::panic::{RefUnwindSafe, UnwindSafe};
66
use std::rc::Rc;
77
use std::task::{Poll, Waker};
88

9-
use async_task::{Builder, Runnable};
9+
use async_task::{Builder, Runnable, Schedule};
1010
use futures_lite::{future, prelude::*};
1111
use slab::Slab;
1212

@@ -103,11 +103,12 @@ impl<'a> LocalExecutor<'a> {
103103
/// });
104104
/// ```
105105
pub fn spawn<T: 'a>(&self, future: impl Future<Output = T> + 'a) -> Task<T> {
106+
let state = self.state_as_rc();
106107
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
107108
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
108109
// values in `State`, including the active field.
109110
let active = unsafe { &mut *self.state().active.get() };
110-
self.spawn_inner(future, active)
111+
Self::spawn_inner(state, future, active, self.schedule())
111112
}
112113

113114
/// Spawns many tasks onto the executor.
@@ -155,30 +156,34 @@ impl<'a> LocalExecutor<'a> {
155156
futures: impl IntoIterator<Item = F>,
156157
handles: &mut impl Extend<Task<F::Output>>,
157158
) {
158-
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
159-
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
160-
// values in `State`, including the active field.
161-
let active = unsafe { &mut *self.state().active.get() };
159+
let tasks = {
160+
let state = self.state_as_rc();
162161

163-
// Convert the futures into tasks.
164-
let tasks = futures
165-
.into_iter()
166-
.map(move |future| self.spawn_inner(future, active));
162+
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
163+
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
164+
// values in `State`, including the active field.
165+
let active = unsafe { &mut *state.active.get() };
166+
167+
// Convert the futures into tasks.
168+
futures.into_iter().map(move |future| {
169+
Self::spawn_inner(state.clone(), future, active, self.schedule())
170+
})
171+
};
167172

168173
// Push the tasks to the user's collection.
169174
handles.extend(tasks);
170175
}
171176

172177
/// Spawn a future while holding the inner lock.
173178
fn spawn_inner<T: 'a>(
174-
&self,
179+
state: Rc<State>,
175180
future: impl Future<Output = T> + 'a,
176181
active: &mut Slab<Waker>,
182+
schedule: impl Schedule + 'static,
177183
) -> Task<T> {
178184
// Remove the task from the set of active tasks when the future finishes.
179185
let entry = active.vacant_entry();
180186
let index = entry.key();
181-
let state = self.state_as_rc();
182187
let future = AsyncCallOnDrop::new(future, move || {
183188
// SAFETY: All UnsafeCell accesses to active are tightly scoped, and because
184189
// `LocalExecutor` is !Send, there is no way to have concurrent access to the
@@ -204,16 +209,16 @@ impl<'a> LocalExecutor<'a> {
204209
// the `Executor` is drained of all of its runnables. This ensures that
205210
// runnables are dropped and this precondition is satisfied.
206211
//
207-
// `self.schedule()` is not `Send` nor `Sync`. As LocalExecutor is not
212+
// `schedule` is not `Send` nor `Sync`. As LocalExecutor is not
208213
// `Send`, the `Waker` is guaranteed// to only be used on the same thread
209214
// it was spawned on.
210215
//
211-
// `self.schedule()` is `'static`, and thus will outlive all borrowed
216+
// `schedule` is `'static`, and thus will outlive all borrowed
212217
// variables in the future.
213218
let (runnable, task) = unsafe {
214219
Builder::new()
215220
.propagate_panic(true)
216-
.spawn_unchecked(|()| future, self.schedule())
221+
.spawn_unchecked(|()| future, schedule)
217222
};
218223
entry.insert(runnable.waker());
219224

0 commit comments

Comments
 (0)