1
- use std:: cell:: RefCell ;
2
- use std:: fmt;
3
- use std:: rc:: Rc ;
4
1
use std:: sync:: atomic:: { AtomicI32 , Ordering } ;
5
2
use std:: sync:: Arc ;
6
3
7
4
use futures:: executor:: { self , Notify , Spawn } ;
8
5
use futures:: future;
9
6
use futures:: prelude:: * ;
10
- use futures:: sync:: oneshot;
11
7
use js_sys:: Function ;
12
8
use wasm_bindgen:: prelude:: * ;
13
9
use wasm_bindgen:: JsCast ;
14
10
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
-
27
11
// Duplicate a bit here because `then` takes a `JsValue` instead of a `Closure`.
28
12
#[ wasm_bindgen]
29
13
extern "C" {
@@ -38,75 +22,6 @@ extern "C" {
38
22
fn get_wait_async ( ) -> JsValue ;
39
23
}
40
24
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
-
110
25
/// Converts a Rust `Future` into a JavaScript `Promise`.
111
26
///
112
27
/// This function will take any future in Rust and schedule it to be executed,
0 commit comments