Skip to content

Commit b13f757

Browse files
committed
Shared more betwee legacy with/without atomics
1 parent be294c8 commit b13f757

File tree

4 files changed

+30
-138
lines changed

4 files changed

+30
-138
lines changed

crates/futures/src/legacy.rs

+5-109
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,11 @@
1-
use std::cell::{Cell, RefCell};
2-
use std::fmt;
3-
use std::rc::Rc;
4-
use std::sync::Arc;
5-
61
use futures::executor::{self, Notify, Spawn};
7-
use futures::future;
82
use futures::prelude::*;
9-
use futures::sync::oneshot;
103
use js_sys::{Function, Promise};
4+
use std::cell::{Cell, RefCell};
5+
use std::rc::Rc;
6+
use std::sync::Arc;
117
use wasm_bindgen::prelude::*;
128

13-
/// A Rust `Future` backed by a JavaScript `Promise`.
14-
///
15-
/// This type is constructed with a JavaScript `Promise` object and translates
16-
/// it to a Rust `Future`. This type implements the `Future` trait from the
17-
/// `futures` crate and will either succeed or fail depending on what happens
18-
/// with the JavaScript `Promise`.
19-
///
20-
/// Currently this type is constructed with `JsFuture::from`.
21-
pub struct JsFuture {
22-
rx: oneshot::Receiver<Result<JsValue, JsValue>>,
23-
}
24-
25-
impl fmt::Debug for JsFuture {
26-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27-
write!(f, "JsFuture {{ ... }}")
28-
}
29-
}
30-
31-
impl From<Promise> for JsFuture {
32-
fn from(js: Promise) -> JsFuture {
33-
// Use the `then` method to schedule two callbacks, one for the
34-
// resolved value and one for the rejected value. We're currently
35-
// assuming that JS engines will unconditionally invoke precisely one of
36-
// these callbacks, no matter what.
37-
//
38-
// Ideally we'd have a way to cancel the callbacks getting invoked and
39-
// free up state ourselves when this `JsFuture` is dropped. We don't
40-
// have that, though, and one of the callbacks is likely always going to
41-
// be invoked.
42-
//
43-
// As a result we need to make sure that no matter when the callbacks
44-
// are invoked they are valid to be called at any time, which means they
45-
// have to be self-contained. Through the `Closure::once` and some
46-
// `Rc`-trickery we can arrange for both instances of `Closure`, and the
47-
// `Rc`, to all be destroyed once the first one is called.
48-
let (tx, rx) = oneshot::channel();
49-
let state = Rc::new(RefCell::new(None));
50-
let state2 = state.clone();
51-
let resolve = Closure::once(move |val| finish(&state2, Ok(val)));
52-
let state2 = state.clone();
53-
let reject = Closure::once(move |val| finish(&state2, Err(val)));
54-
55-
js.then2(&resolve, &reject);
56-
*state.borrow_mut() = Some((tx, resolve, reject));
57-
58-
return JsFuture { rx };
59-
60-
fn finish(
61-
state: &RefCell<
62-
Option<(
63-
oneshot::Sender<Result<JsValue, JsValue>>,
64-
Closure<dyn FnMut(JsValue)>,
65-
Closure<dyn FnMut(JsValue)>,
66-
)>,
67-
>,
68-
val: Result<JsValue, JsValue>,
69-
) {
70-
match state.borrow_mut().take() {
71-
// We don't have any guarantee that anyone's still listening at this
72-
// point (the Rust `JsFuture` could have been dropped) so simply
73-
// ignore any errors here.
74-
Some((tx, _, _)) => drop(tx.send(val)),
75-
None => wasm_bindgen::throw_str("cannot finish twice"),
76-
}
77-
}
78-
}
79-
}
80-
81-
impl Future for JsFuture {
82-
type Item = JsValue;
83-
type Error = JsValue;
84-
85-
fn poll(&mut self) -> Poll<JsValue, JsValue> {
86-
match self.rx.poll() {
87-
Ok(Async::Ready(val)) => val.map(Async::Ready),
88-
Ok(Async::NotReady) => Ok(Async::NotReady),
89-
Err(_) => wasm_bindgen::throw_str("cannot cancel"),
90-
}
91-
}
92-
}
93-
949
/// Converts a Rust `Future` into a JavaScript `Promise`.
9510
///
9611
/// This function will take any future in Rust and schedule it to be executed,
@@ -112,8 +27,8 @@ impl Future for JsFuture {
11227
/// resolve**. Instead it will be a leaked promise. This is an unfortunate
11328
/// limitation of wasm currently that's hoped to be fixed one day!
11429
pub fn future_to_promise<F>(future: F) -> Promise
115-
where
116-
F: Future<Item = JsValue, Error = JsValue> + 'static,
30+
where
31+
F: Future<Item = JsValue, Error = JsValue> + 'static,
11732
{
11833
_future_to_promise(Box::new(future))
11934
}
@@ -287,22 +202,3 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
287202
}
288203
}
289204
}
290-
291-
/// Converts a Rust `Future` on a local task queue.
292-
///
293-
/// The `future` provided must adhere to `'static` because it'll be scheduled
294-
/// to run in the background and cannot contain any stack references.
295-
///
296-
/// # Panics
297-
///
298-
/// This function has the same panic behavior as `future_to_promise`.
299-
pub fn spawn_local<F>(future: F)
300-
where
301-
F: Future<Item = (), Error = ()> + 'static,
302-
{
303-
future_to_promise(
304-
future
305-
.map(|()| JsValue::undefined())
306-
.or_else(|()| future::ok::<JsValue, JsValue>(JsValue::undefined())),
307-
);
308-
}

crates/futures/src/legacy_atomics.rs

+2-24
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
use std::sync::atomic::{AtomicI32, Ordering};
2-
use std::sync::Arc;
3-
41
use futures::executor::{self, Notify, Spawn};
5-
use futures::future;
62
use futures::prelude::*;
73
use js_sys::Function;
4+
use std::sync::atomic::{AtomicI32, Ordering};
5+
use std::sync::Arc;
86
use wasm_bindgen::prelude::*;
97
use wasm_bindgen::JsCast;
108

@@ -165,24 +163,4 @@ fn wait_async(ptr: &AtomicI32, val: i32) -> js_sys::Promise {
165163
let mem = wasm_bindgen::memory().unchecked_into::<js_sys::WebAssembly::Memory>();
166164
Atomics::wait_async(&mem.buffer(), ptr as *const AtomicI32 as i32 / 4, val)
167165
}
168-
169-
}
170-
171-
/// Converts a Rust `Future` on a local task queue.
172-
///
173-
/// The `future` provided must adhere to `'static` because it'll be scheduled
174-
/// to run in the background and cannot contain any stack references.
175-
///
176-
/// # Panics
177-
///
178-
/// This function has the same panic behavior as `future_to_promise`.
179-
pub fn spawn_local<F>(future: F)
180-
where
181-
F: Future<Item = (), Error = ()> + 'static,
182-
{
183-
future_to_promise(
184-
future
185-
.map(|()| JsValue::undefined())
186-
.or_else(|()| future::ok::<JsValue, JsValue>(JsValue::undefined())),
187-
);
188166
}

crates/futures/src/legacy_js2rust.rs renamed to crates/futures/src/legacy_shared.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cell::RefCell;
2+
use futures::future;
23
use std::fmt;
34
use std::rc::Rc;
4-
55
use futures::prelude::*;
66
use futures::sync::oneshot;
77
use js_sys::Promise;
@@ -87,3 +87,22 @@ impl Future for JsFuture {
8787
}
8888
}
8989
}
90+
91+
/// Converts a Rust `Future` on a local task queue.
92+
///
93+
/// The `future` provided must adhere to `'static` because it'll be scheduled
94+
/// to run in the background and cannot contain any stack references.
95+
///
96+
/// # Panics
97+
///
98+
/// This function has the same panic behavior as `future_to_promise`.
99+
pub fn spawn_local<F>(future: F)
100+
where
101+
F: Future<Item = (), Error = ()> + 'static,
102+
{
103+
crate::future_to_promise(
104+
future
105+
.map(|()| JsValue::undefined())
106+
.or_else(|()| future::ok::<JsValue, JsValue>(JsValue::undefined())),
107+
);
108+
}

crates/futures/src/lib.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -106,18 +106,17 @@
106106

107107
use cfg_if::cfg_if;
108108

109-
mod legacy_js2rust;
110-
pub use legacy_js2rust::*;
109+
mod legacy_shared;
110+
pub use legacy_shared::*;
111111

112112
cfg_if! {
113113
if #[cfg(target_feature = "atomics")] {
114114
/// Contains a thread-safe version of this crate, with Futures 0.1
115115
mod legacy_atomics;
116+
pub use legacy_atomics::*;
116117

117118
/// Polyfill for `Atomics.waitAsync` function
118119
mod wait_async_polyfill;
119-
120-
pub use legacy_atomics::*;
121120
} else {
122121
mod legacy;
123122
pub use legacy::*;

0 commit comments

Comments
 (0)