Skip to content

Commit 6c58afd

Browse files
committed
Addressing feedback
1 parent 69d7dc2 commit 6c58afd

File tree

4 files changed

+331
-334
lines changed

4 files changed

+331
-334
lines changed

crates/futures/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ lazy_static = { version = "1.3.0", optional = true }
2222
wasm-bindgen-test = { path = '../test', version = '0.2.43' }
2323

2424
[features]
25-
nightly = ["futures-util-preview", "futures-channel-preview", "lazy_static"]
25+
futures_0_3 = ["futures-util-preview", "futures-channel-preview", "lazy_static"]

crates/futures/src/nightly.rs renamed to crates/futures/src/futures_0_3.rs

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::fmt;
22
use std::pin::Pin;
3-
use std::sync::{Arc, Mutex};
4-
use std::sync::atomic::{AtomicBool, Ordering};
3+
use std::cell::{Cell, RefCell};
4+
use std::sync::Arc;
55
use std::future::Future;
66
use std::task::{Poll, Context};
77
use std::collections::VecDeque;
@@ -138,44 +138,46 @@ where
138138
F: Future<Output = ()> + 'static,
139139
{
140140
struct Task {
141-
future: Mutex<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>,
142-
is_queued: AtomicBool,
141+
// This is an Option so that the Future can be immediately dropped when it's finished
142+
future: RefCell<Option<Pin<Box<dyn Future<Output = ()> + 'static>>>>,
143+
is_queued: Cell<bool>,
143144
}
144145

145146
impl Task {
146147
#[inline]
147148
fn new<F>(future: F) -> Arc<Self> where F: Future<Output = ()> + 'static {
148149
Arc::new(Self {
149-
future: Mutex::new(Some(Box::pin(future))),
150-
is_queued: AtomicBool::new(false),
150+
future: RefCell::new(Some(Box::pin(future))),
151+
is_queued: Cell::new(false),
151152
})
152153
}
153154
}
154155

155156
impl ArcWake for Task {
156157
fn wake_by_ref(arc_self: &Arc<Self>) {
157-
// TODO can this be more relaxed ?
158-
if !arc_self.is_queued.swap(true, Ordering::SeqCst) {
159-
let mut lock = EXECUTOR.tasks.lock().unwrap_throw();
158+
if arc_self.is_queued.replace(true) {
159+
return;
160+
}
160161

161-
lock.push_back(arc_self.clone());
162+
let mut lock = EXECUTOR.tasks.borrow_mut();
162163

163-
EXECUTOR.next_tick.schedule();
164-
}
164+
lock.push_back(arc_self.clone());
165+
166+
EXECUTOR.next_tick.schedule();
165167
}
166168
}
167169

168170

169171
struct NextTick {
170-
is_spinning: AtomicBool,
172+
is_spinning: Cell<bool>,
171173
promise: Promise,
172174
closure: Closure<dyn FnMut(JsValue)>,
173175
}
174176

175177
impl NextTick {
176178
fn new<F>(mut f: F) -> Self where F: FnMut() + 'static {
177179
Self {
178-
is_spinning: AtomicBool::new(false),
180+
is_spinning: Cell::new(false),
179181
promise: Promise::resolve(&JsValue::null()),
180182
closure: Closure::wrap(Box::new(move |_| {
181183
f();
@@ -184,22 +186,22 @@ where
184186
}
185187

186188
fn schedule(&self) {
187-
// TODO can this be more relaxed ?
188-
if !self.is_spinning.swap(true, Ordering::SeqCst) {
189-
// TODO avoid creating a new Promise
190-
self.promise.then(&self.closure);
189+
if self.is_spinning.replace(true) {
190+
return;
191191
}
192+
193+
// TODO avoid creating a new Promise
194+
self.promise.then(&self.closure);
192195
}
193196

194197
fn done(&self) {
195-
// TODO can this be more relaxed ?
196-
self.is_spinning.store(false, Ordering::SeqCst);
198+
self.is_spinning.set(false);
197199
}
198200
}
199201

200202

201203
struct Executor {
202-
tasks: Mutex<VecDeque<Arc<Task>>>,
204+
tasks: RefCell<VecDeque<Arc<Task>>>,
203205
next_tick: NextTick,
204206
}
205207

@@ -209,31 +211,33 @@ where
209211

210212
lazy_static! {
211213
static ref EXECUTOR: Executor = Executor {
212-
tasks: Mutex::new(VecDeque::new()),
214+
tasks: RefCell::new(VecDeque::new()),
213215
next_tick: NextTick::new(|| {
214216
let tasks = &EXECUTOR.tasks;
215217

216218
loop {
217-
let mut lock = tasks.lock().unwrap_throw();
219+
let mut lock = tasks.borrow_mut();
218220

219221
match lock.pop_front() {
220222
Some(task) => {
221223
// This is necessary because the polled task might queue more tasks
222224
drop(lock);
223225

224-
let mut future = task.future.lock().unwrap_throw();
226+
let mut future = task.future.borrow_mut();
227+
228+
let poll = {
229+
let mut future = future.as_mut().unwrap_throw();
225230

226-
let poll = future.as_mut().map(|mut future| {
227231
// Clear `is_queued` flag so that it will re-queue if poll calls waker.wake()
228-
task.is_queued.store(false, Ordering::SeqCst);
232+
task.is_queued.set(false);
229233

230234
// TODO is there some way of saving these so they don't need to be recreated all the time ?
231235
let waker = ArcWake::into_waker(task.clone());
232236
let cx = &mut Context::from_waker(&waker);
233237
Pin::new(&mut future).poll(cx)
234-
});
238+
};
235239

236-
if let Some(Poll::Ready(_)) = poll {
240+
if let Poll::Ready(_) = poll {
237241
*future = None;
238242
}
239243
},

0 commit comments

Comments
 (0)