Pauan bdcf27c7cb Major improvements to wasm-bindgen-futures (#1760)
This PR contains a few major improvements:

* Code duplication has been removed.

* Everything has been refactored so that the implementation is much easier to understand.

* `future_to_promise` is now implemented with `spawn_local` rather than the other way around (this means `spawn_local` is faster since it doesn't need to create an unneeded `Promise`).

* Both the single threaded and multi threaded executors have been rewritten from scratch:

   * They only create 1-2 allocations in Rust per Task, and all of the allocations happen when the Task is created.

   * The singlethreaded executor creates 1 Promise per tick, rather than 1 Promise per tick per Task.

   * Both executors do *not* create `Closure`s during polling, instead all needed `Closure`s are created ahead of time.

   * Both executors now have correct behavior with regard to spurious wakeups and waking up during the call to `poll`.

   * Both executors cache the `Waker` so it doesn't need to be recreated all the time.

I believe both executors are now optimal in terms of both Rust and JS performance.
2019-09-26 13:33:12 -05:00

91 lines
2.3 KiB
Rust

#![cfg(target_arch = "wasm32")]
wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
use futures_channel::oneshot;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::{future_to_promise, spawn_local, JsFuture};
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
async fn promise_resolve_is_ok_future() {
let p = js_sys::Promise::resolve(&JsValue::from(42));
let x = JsFuture::from(p).await.unwrap();
assert_eq!(x, 42);
}
#[wasm_bindgen_test]
async fn promise_reject_is_error_future() {
let p = js_sys::Promise::reject(&JsValue::from(42));
let e = JsFuture::from(p).await.unwrap_err();
assert_eq!(e, 42);
}
#[wasm_bindgen_test]
async fn ok_future_is_resolved_promise() {
let p = future_to_promise(async { Ok(JsValue::from(42)) });
let x = JsFuture::from(p).await.unwrap();
assert_eq!(x, 42);
}
#[wasm_bindgen_test]
async fn error_future_is_rejected_promise() {
let p = future_to_promise(async { Err(JsValue::from(42)) });
let e = JsFuture::from(p).await.unwrap_err();
assert_eq!(e, 42);
}
#[wasm_bindgen_test]
fn debug_jsfuture() {
let p = js_sys::Promise::resolve(&JsValue::from(42));
let f = JsFuture::from(p);
assert_eq!(&format!("{:?}", f), "JsFuture { ... }");
}
#[wasm_bindgen]
extern "C" {
fn setTimeout(c: &Closure<dyn FnMut()>);
}
#[wasm_bindgen_test]
async fn oneshot_works() {
let (tx, rx) = oneshot::channel::<u32>();
let mut tx = Some(tx);
let closure = Closure::wrap(Box::new(move || {
drop(tx.take().unwrap());
}) as Box<dyn FnMut()>);
setTimeout(&closure);
closure.forget();
rx.await.unwrap_err();
}
#[wasm_bindgen_test]
async fn spawn_local_runs() {
let (tx, rx) = oneshot::channel::<u32>();
spawn_local(async {
tx.send(42).unwrap();
});
assert_eq!(rx.await.unwrap(), 42);
}
#[wasm_bindgen_test]
async fn spawn_local_err_no_exception() {
let (tx, rx) = oneshot::channel::<u32>();
spawn_local(async {});
spawn_local(async {
tx.send(42).unwrap();
});
let val = rx.await.unwrap();
assert_eq!(val, 42);
}
#[wasm_bindgen_test]
async fn can_create_multiple_futures_from_same_promise() {
let promise = js_sys::Promise::resolve(&JsValue::null());
let a = JsFuture::from(promise.clone());
let b = JsFuture::from(promise);
a.await.unwrap();
b.await.unwrap();
}