Skip to content

Commit d590a9e

Browse files
committed
Deduplicate JsFuture definitions
Turns out it's the exact same for both before and after atomics, so let's use the same definition!
1 parent cde9684 commit d590a9e

File tree

3 files changed

+92
-85
lines changed

3 files changed

+92
-85
lines changed

crates/futures/src/atomics.rs

Lines changed: 0 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,13 @@
1-
use std::cell::RefCell;
2-
use std::fmt;
3-
use std::rc::Rc;
41
use std::sync::atomic::{AtomicI32, Ordering};
52
use std::sync::Arc;
63

74
use futures::executor::{self, Notify, Spawn};
85
use futures::future;
96
use futures::prelude::*;
10-
use futures::sync::oneshot;
117
use js_sys::Function;
128
use wasm_bindgen::prelude::*;
139
use wasm_bindgen::JsCast;
1410

15-
/// A Rust `Future` backed by a JavaScript `Promise`.
16-
///
17-
/// This type is constructed with a JavaScript `Promise` object and translates
18-
/// it to a Rust `Future`. This type implements the `Future` trait from the
19-
/// `futures` crate and will either succeed or fail depending on what happens
20-
/// with the JavaScript `Promise`.
21-
///
22-
/// Currently this type is constructed with `JsFuture::from`.
23-
pub struct JsFuture {
24-
rx: oneshot::Receiver<Result<JsValue, JsValue>>,
25-
}
26-
2711
// Duplicate a bit here because `then` takes a `JsValue` instead of a `Closure`.
2812
#[wasm_bindgen]
2913
extern "C" {
@@ -38,75 +22,6 @@ extern "C" {
3822
fn get_wait_async() -> JsValue;
3923
}
4024

41-
impl fmt::Debug for JsFuture {
42-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43-
write!(f, "JsFuture {{ ... }}")
44-
}
45-
}
46-
47-
impl From<js_sys::Promise> for JsFuture {
48-
fn from(js: js_sys::Promise) -> JsFuture {
49-
// Use the `then` method to schedule two callbacks, one for the
50-
// resolved value and one for the rejected value. We're currently
51-
// assuming that JS engines will unconditionally invoke precisely one of
52-
// these callbacks, no matter what.
53-
//
54-
// Ideally we'd have a way to cancel the callbacks getting invoked and
55-
// free up state ourselves when this `JsFuture` is dropped. We don't
56-
// have that, though, and one of the callbacks is likely always going to
57-
// be invoked.
58-
//
59-
// As a result we need to make sure that no matter when the callbacks
60-
// are invoked they are valid to be called at any time, which means they
61-
// have to be self-contained. Through the `Closure::once` and some
62-
// `Rc`-trickery we can arrange for both instances of `Closure`, and the
63-
// `Rc`, to all be destroyed once the first one is called.
64-
let (tx, rx) = oneshot::channel();
65-
let state = Rc::new(RefCell::new(None));
66-
let state2 = state.clone();
67-
let resolve = Closure::once(move |val| finish(&state2, Ok(val)));
68-
let state2 = state.clone();
69-
let reject = Closure::once(move |val| finish(&state2, Err(val)));
70-
71-
js.then2(&resolve, &reject);
72-
*state.borrow_mut() = Some((tx, resolve, reject));
73-
74-
return JsFuture { rx };
75-
76-
fn finish(
77-
state: &RefCell<
78-
Option<(
79-
oneshot::Sender<Result<JsValue, JsValue>>,
80-
Closure<dyn FnMut(JsValue)>,
81-
Closure<dyn FnMut(JsValue)>,
82-
)>,
83-
>,
84-
val: Result<JsValue, JsValue>,
85-
) {
86-
match state.borrow_mut().take() {
87-
// We don't have any guarantee that anyone's still listening at this
88-
// point (the Rust `JsFuture` could have been dropped) so simply
89-
// ignore any errors here.
90-
Some((tx, _, _)) => drop(tx.send(val)),
91-
None => wasm_bindgen::throw_str("cannot finish twice"),
92-
}
93-
}
94-
}
95-
}
96-
97-
impl Future for JsFuture {
98-
type Item = JsValue;
99-
type Error = JsValue;
100-
101-
fn poll(&mut self) -> Poll<JsValue, JsValue> {
102-
match self.rx.poll() {
103-
Ok(Async::Ready(val)) => val.map(Async::Ready),
104-
Ok(Async::NotReady) => Ok(Async::NotReady),
105-
Err(_) => wasm_bindgen::throw_str("cannot cancel"),
106-
}
107-
}
108-
}
109-
11025
/// Converts a Rust `Future` into a JavaScript `Promise`.
11126
///
11227
/// This function will take any future in Rust and schedule it to be executed,

crates/futures/src/legacy_js2rust.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use std::cell::RefCell;
2+
use std::fmt;
3+
use std::rc::Rc;
4+
5+
use futures::prelude::*;
6+
use futures::sync::oneshot;
7+
use js_sys::Promise;
8+
use wasm_bindgen::prelude::*;
9+
10+
/// A Rust `Future` backed by a JavaScript `Promise`.
11+
///
12+
/// This type is constructed with a JavaScript `Promise` object and translates
13+
/// it to a Rust `Future`. This type implements the `Future` trait from the
14+
/// `futures` crate and will either succeed or fail depending on what happens
15+
/// with the JavaScript `Promise`.
16+
///
17+
/// Currently this type is constructed with `JsFuture::from`.
18+
pub struct JsFuture {
19+
rx: oneshot::Receiver<Result<JsValue, JsValue>>,
20+
}
21+
22+
impl fmt::Debug for JsFuture {
23+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24+
write!(f, "JsFuture {{ ... }}")
25+
}
26+
}
27+
28+
impl From<Promise> for JsFuture {
29+
fn from(js: Promise) -> JsFuture {
30+
// Use the `then` method to schedule two callbacks, one for the
31+
// resolved value and one for the rejected value. We're currently
32+
// assuming that JS engines will unconditionally invoke precisely one of
33+
// these callbacks, no matter what.
34+
//
35+
// Ideally we'd have a way to cancel the callbacks getting invoked and
36+
// free up state ourselves when this `JsFuture` is dropped. We don't
37+
// have that, though, and one of the callbacks is likely always going to
38+
// be invoked.
39+
//
40+
// As a result we need to make sure that no matter when the callbacks
41+
// are invoked they are valid to be called at any time, which means they
42+
// have to be self-contained. Through the `Closure::once` and some
43+
// `Rc`-trickery we can arrange for both instances of `Closure`, and the
44+
// `Rc`, to all be destroyed once the first one is called.
45+
let (tx, rx) = oneshot::channel();
46+
let state = Rc::new(RefCell::new(None));
47+
let state2 = state.clone();
48+
let resolve = Closure::once(move |val| finish(&state2, Ok(val)));
49+
let state2 = state.clone();
50+
let reject = Closure::once(move |val| finish(&state2, Err(val)));
51+
52+
js.then2(&resolve, &reject);
53+
*state.borrow_mut() = Some((tx, resolve, reject));
54+
55+
return JsFuture { rx };
56+
57+
fn finish(
58+
state: &RefCell<
59+
Option<(
60+
oneshot::Sender<Result<JsValue, JsValue>>,
61+
Closure<dyn FnMut(JsValue)>,
62+
Closure<dyn FnMut(JsValue)>,
63+
)>,
64+
>,
65+
val: Result<JsValue, JsValue>,
66+
) {
67+
match state.borrow_mut().take() {
68+
// We don't have any guarantee that anyone's still listening at this
69+
// point (the Rust `JsFuture` could have been dropped) so simply
70+
// ignore any errors here.
71+
Some((tx, _, _)) => drop(tx.send(val)),
72+
None => wasm_bindgen::throw_str("cannot finish twice"),
73+
}
74+
}
75+
}
76+
}
77+
78+
impl Future for JsFuture {
79+
type Item = JsValue;
80+
type Error = JsValue;
81+
82+
fn poll(&mut self) -> Poll<JsValue, JsValue> {
83+
match self.rx.poll() {
84+
Ok(Async::Ready(val)) => val.map(Async::Ready),
85+
Ok(Async::NotReady) => Ok(Async::NotReady),
86+
Err(_) => wasm_bindgen::throw_str("cannot cancel"),
87+
}
88+
}
89+
}

crates/futures/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@
106106

107107
use cfg_if::cfg_if;
108108

109+
mod legacy_js2rust;
110+
pub use legacy_js2rust::*;
111+
109112
cfg_if! {
110113
if #[cfg(target_feature = "atomics")] {
111114
/// Contains a thread-safe version of this crate, with Futures 0.1

0 commit comments

Comments
 (0)