1
- use std:: cell:: { Cell , RefCell } ;
2
- use std:: fmt;
3
- use std:: rc:: Rc ;
4
- use std:: sync:: Arc ;
5
-
6
1
use futures:: executor:: { self , Notify , Spawn } ;
7
- use futures:: future;
8
2
use futures:: prelude:: * ;
9
- use futures:: sync:: oneshot;
10
3
use js_sys:: { Function , Promise } ;
4
+ use std:: cell:: { Cell , RefCell } ;
5
+ use std:: rc:: Rc ;
6
+ use std:: sync:: Arc ;
11
7
use wasm_bindgen:: prelude:: * ;
12
8
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
-
94
9
/// Converts a Rust `Future` into a JavaScript `Promise`.
95
10
///
96
11
/// This function will take any future in Rust and schedule it to be executed,
@@ -112,8 +27,8 @@ impl Future for JsFuture {
112
27
/// resolve**. Instead it will be a leaked promise. This is an unfortunate
113
28
/// limitation of wasm currently that's hoped to be fixed one day!
114
29
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 ,
117
32
{
118
33
_future_to_promise ( Box :: new ( future) )
119
34
}
@@ -287,22 +202,3 @@ fn _future_to_promise(future: Box<dyn Future<Item = JsValue, Error = JsValue>>)
287
202
}
288
203
}
289
204
}
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
- }
0 commit comments