summaryrefslogtreecommitdiffstats
path: root/vendor/wasm-bindgen-futures
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /vendor/wasm-bindgen-futures
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/wasm-bindgen-futures')
-rw-r--r--vendor/wasm-bindgen-futures/.cargo-checksum.json1
-rw-r--r--vendor/wasm-bindgen-futures/Cargo.toml56
-rw-r--r--vendor/wasm-bindgen-futures/LICENSE-APACHE201
-rw-r--r--vendor/wasm-bindgen-futures/LICENSE-MIT25
-rw-r--r--vendor/wasm-bindgen-futures/README.md16
-rw-r--r--vendor/wasm-bindgen-futures/src/lib.rs229
-rw-r--r--vendor/wasm-bindgen-futures/src/queue.rs91
-rw-r--r--vendor/wasm-bindgen-futures/src/stream.rs81
-rw-r--r--vendor/wasm-bindgen-futures/src/task/multithread.rs201
-rw-r--r--vendor/wasm-bindgen-futures/src/task/singlethread.rs113
-rw-r--r--vendor/wasm-bindgen-futures/src/task/wait_async_polyfill.rs91
-rw-r--r--vendor/wasm-bindgen-futures/src/task/worker.js6
-rw-r--r--vendor/wasm-bindgen-futures/tests/tests.rs157
13 files changed, 1268 insertions, 0 deletions
diff --git a/vendor/wasm-bindgen-futures/.cargo-checksum.json b/vendor/wasm-bindgen-futures/.cargo-checksum.json
new file mode 100644
index 000000000..ea84514d2
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"ee7ebbb384e7bad80c2e62af9c6fd2b9eab4af7e95d0e93cedb1410c7952395a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"85d37419c6d458e5076b37ed6f06471491b1b16b29dc1e37972117ed2818652d","src/lib.rs":"6c3a7fb9a25793434861f66bab405b5f446407a2b46055bb45bf87b7593a262e","src/queue.rs":"80fe49bc6a7235ce3388d6871da5a24e0fd3c32da0e19d96eeb5f60922167348","src/stream.rs":"5e83d72eb8c339ef0208c367da0004160c9f567ac744bc66e8e49de9589a1825","src/task/multithread.rs":"d25b63e2f0679bce9e79aa85b4c94afb6ba656118f7e813b84eb96f384448bd0","src/task/singlethread.rs":"623a221b4db670588ae115627a9b7f81e21f4827259ac719abb7ef5b1cefa9a5","src/task/wait_async_polyfill.rs":"6245e6c6040b36025aed6b2d880866ede6e7bd97ec68676d0a754c09916f440c","src/task/worker.js":"1f1b207b7f45925d8c50f51538d3c23caf14073080bfe6e6bc64a3689b93db78","tests/tests.rs":"7ad80fd9f0ba3b1d05015d05fbdc16891b81ac1d975e0498c04b503fbf62c3e8"},"package":"f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"} \ No newline at end of file
diff --git a/vendor/wasm-bindgen-futures/Cargo.toml b/vendor/wasm-bindgen-futures/Cargo.toml
new file mode 100644
index 000000000..885246b36
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/Cargo.toml
@@ -0,0 +1,56 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+name = "wasm-bindgen-futures"
+version = "0.4.34"
+authors = ["The wasm-bindgen Developers"]
+description = "Bridging the gap between Rust Futures and JavaScript Promises"
+homepage = "https://rustwasm.github.io/wasm-bindgen/"
+documentation = "https://docs.rs/wasm-bindgen-futures"
+readme = "./README.md"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures"
+
+[dependencies.cfg-if]
+version = "1.0.0"
+
+[dependencies.futures-core]
+version = "0.3.8"
+optional = true
+default-features = false
+
+[dependencies.js-sys]
+version = "0.3.61"
+
+[dependencies.wasm-bindgen]
+version = "0.2.84"
+
+[features]
+futures-core-03-stream = ["futures-core"]
+
+[target."cfg(target_arch = \"wasm32\")".dev-dependencies.futures-channel-preview]
+version = "0.3.0-alpha.18"
+
+[target."cfg(target_arch = \"wasm32\")".dev-dependencies.futures-lite]
+version = "1.11.3"
+default-features = false
+
+[target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test]
+version = "0.3.34"
+
+[target."cfg(target_feature = \"atomics\")".dependencies.web-sys]
+version = "0.3.24"
+features = [
+ "MessageEvent",
+ "Worker",
+]
diff --git a/vendor/wasm-bindgen-futures/LICENSE-APACHE b/vendor/wasm-bindgen-futures/LICENSE-APACHE
new file mode 100644
index 000000000..16fe87b06
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/vendor/wasm-bindgen-futures/LICENSE-MIT b/vendor/wasm-bindgen-futures/LICENSE-MIT
new file mode 100644
index 000000000..39e0ed660
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 Alex Crichton
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/vendor/wasm-bindgen-futures/README.md b/vendor/wasm-bindgen-futures/README.md
new file mode 100644
index 000000000..eb0a067f3
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/README.md
@@ -0,0 +1,16 @@
+# `wasm-bindgen-futures`
+
+[API Documention][docs]
+
+This crate bridges the gap between a Rust `Future` and a JavaScript
+`Promise`. It provides two conversions:
+
+1. From a JavaScript `Promise` into a Rust `Future`.
+2. From a Rust `Future` into a JavaScript `Promise`.
+
+Additionally under the feature flag `futures-core-03-stream` there is experimental
+support for `AsyncIterator` to `Stream` conversion.
+
+See the [API documentation][docs] for more info.
+
+[docs]: https://rustwasm.github.io/wasm-bindgen/api/wasm_bindgen_futures/
diff --git a/vendor/wasm-bindgen-futures/src/lib.rs b/vendor/wasm-bindgen-futures/src/lib.rs
new file mode 100644
index 000000000..c2a59d762
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/lib.rs
@@ -0,0 +1,229 @@
+//! Converting between JavaScript `Promise`s to Rust `Future`s.
+//!
+//! This crate provides a bridge for working with JavaScript `Promise` types as
+//! a Rust `Future`, and similarly contains utilities to turn a rust `Future`
+//! into a JavaScript `Promise`. This can be useful when working with
+//! asynchronous or otherwise blocking work in Rust (wasm), and provides the
+//! ability to interoperate with JavaScript events and JavaScript I/O
+//! primitives.
+//!
+//! There are three main interfaces in this crate currently:
+//!
+//! 1. [**`JsFuture`**](./struct.JsFuture.html)
+//!
+//! A type that is constructed with a `Promise` and can then be used as a
+//! `Future<Output = Result<JsValue, JsValue>>`. This Rust future will resolve
+//! or reject with the value coming out of the `Promise`.
+//!
+//! 2. [**`future_to_promise`**](./fn.future_to_promise.html)
+//!
+//! Converts a Rust `Future<Output = Result<JsValue, JsValue>>` into a
+//! JavaScript `Promise`. The future's result will translate to either a
+//! resolved or rejected `Promise` in JavaScript.
+//!
+//! 3. [**`spawn_local`**](./fn.spawn_local.html)
+//!
+//! Spawns a `Future<Output = ()>` on the current thread. This is the
+//! best way to run a `Future` in Rust without sending it to JavaScript.
+//!
+//! These three items should provide enough of a bridge to interoperate the two
+//! systems and make sure that Rust/JavaScript can work together with
+//! asynchronous and I/O work.
+
+#![cfg_attr(target_feature = "atomics", feature(stdsimd))]
+#![deny(missing_docs)]
+
+use js_sys::Promise;
+use std::cell::RefCell;
+use std::fmt;
+use std::future::Future;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::task::{Context, Poll, Waker};
+use wasm_bindgen::prelude::*;
+
+mod queue;
+#[cfg(feature = "futures-core-03-stream")]
+pub mod stream;
+
+mod task {
+ use cfg_if::cfg_if;
+
+ cfg_if! {
+ if #[cfg(target_feature = "atomics")] {
+ mod wait_async_polyfill;
+ mod multithread;
+ pub(crate) use multithread::*;
+
+ } else {
+ mod singlethread;
+ pub(crate) use singlethread::*;
+ }
+ }
+}
+
+/// Runs a Rust `Future` on the current thread.
+///
+/// The `future` must be `'static` because it will be scheduled
+/// to run in the background and cannot contain any stack references.
+///
+/// The `future` will always be run on the next microtask tick even if it
+/// immediately returns `Poll::Ready`.
+///
+/// # Panics
+///
+/// This function has the same panic behavior as `future_to_promise`.
+#[inline]
+pub fn spawn_local<F>(future: F)
+where
+ F: Future<Output = ()> + 'static,
+{
+ task::Task::spawn(Box::pin(future));
+}
+
+struct Inner {
+ result: Option<Result<JsValue, JsValue>>,
+ task: Option<Waker>,
+ callbacks: Option<(Closure<dyn FnMut(JsValue)>, Closure<dyn FnMut(JsValue)>)>,
+}
+
+/// A Rust `Future` backed by a JavaScript `Promise`.
+///
+/// This type is constructed with a JavaScript `Promise` object and translates
+/// it to a Rust `Future`. This type implements the `Future` trait from the
+/// `futures` crate and will either succeed or fail depending on what happens
+/// with the JavaScript `Promise`.
+///
+/// Currently this type is constructed with `JsFuture::from`.
+pub struct JsFuture {
+ inner: Rc<RefCell<Inner>>,
+}
+
+impl fmt::Debug for JsFuture {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "JsFuture {{ ... }}")
+ }
+}
+
+impl From<Promise> for JsFuture {
+ fn from(js: Promise) -> JsFuture {
+ // Use the `then` method to schedule two callbacks, one for the
+ // resolved value and one for the rejected value. We're currently
+ // assuming that JS engines will unconditionally invoke precisely one of
+ // these callbacks, no matter what.
+ //
+ // Ideally we'd have a way to cancel the callbacks getting invoked and
+ // free up state ourselves when this `JsFuture` is dropped. We don't
+ // have that, though, and one of the callbacks is likely always going to
+ // be invoked.
+ //
+ // As a result we need to make sure that no matter when the callbacks
+ // are invoked they are valid to be called at any time, which means they
+ // have to be self-contained. Through the `Closure::once` and some
+ // `Rc`-trickery we can arrange for both instances of `Closure`, and the
+ // `Rc`, to all be destroyed once the first one is called.
+ let state = Rc::new(RefCell::new(Inner {
+ result: None,
+ task: None,
+ callbacks: None,
+ }));
+
+ fn finish(state: &RefCell<Inner>, val: Result<JsValue, JsValue>) {
+ let task = {
+ let mut state = state.borrow_mut();
+ debug_assert!(state.callbacks.is_some());
+ debug_assert!(state.result.is_none());
+
+ // First up drop our closures as they'll never be invoked again and
+ // this is our chance to clean up their state.
+ drop(state.callbacks.take());
+
+ // Next, store the value into the internal state.
+ state.result = Some(val);
+ state.task.take()
+ };
+
+ // And then finally if any task was waiting on the value wake it up and
+ // let them know it's there.
+ if let Some(task) = task {
+ task.wake()
+ }
+ }
+
+ let resolve = {
+ let state = state.clone();
+ Closure::once(move |val| finish(&state, Ok(val)))
+ };
+
+ let reject = {
+ let state = state.clone();
+ Closure::once(move |val| finish(&state, Err(val)))
+ };
+
+ let _ = js.then2(&resolve, &reject);
+
+ state.borrow_mut().callbacks = Some((resolve, reject));
+
+ JsFuture { inner: state }
+ }
+}
+
+impl Future for JsFuture {
+ type Output = Result<JsValue, JsValue>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+ let mut inner = self.inner.borrow_mut();
+
+ // If our value has come in then we return it...
+ if let Some(val) = inner.result.take() {
+ return Poll::Ready(val);
+ }
+
+ // ... otherwise we arrange ourselves to get woken up once the value
+ // does come in
+ inner.task = Some(cx.waker().clone());
+ Poll::Pending
+ }
+}
+
+/// Converts a Rust `Future` into a JavaScript `Promise`.
+///
+/// This function will take any future in Rust and schedule it to be executed,
+/// returning a JavaScript `Promise` which can then be passed to JavaScript.
+///
+/// The `future` must be `'static` because it will be scheduled to run in the
+/// background and cannot contain any stack references.
+///
+/// The returned `Promise` will be resolved or rejected when the future completes,
+/// depending on whether it finishes with `Ok` or `Err`.
+///
+/// # Panics
+///
+/// Note that in wasm panics are currently translated to aborts, but "abort" in
+/// this case means that a JavaScript exception is thrown. The wasm module is
+/// still usable (likely erroneously) after Rust panics.
+///
+/// If the `future` provided panics then the returned `Promise` **will not
+/// resolve**. Instead it will be a leaked promise. This is an unfortunate
+/// limitation of wasm currently that's hoped to be fixed one day!
+pub fn future_to_promise<F>(future: F) -> Promise
+where
+ F: Future<Output = Result<JsValue, JsValue>> + 'static,
+{
+ let mut future = Some(future);
+
+ Promise::new(&mut |resolve, reject| {
+ let future = future.take().unwrap_throw();
+
+ spawn_local(async move {
+ match future.await {
+ Ok(val) => {
+ resolve.call1(&JsValue::undefined(), &val).unwrap_throw();
+ }
+ Err(val) => {
+ reject.call1(&JsValue::undefined(), &val).unwrap_throw();
+ }
+ }
+ });
+ })
+}
diff --git a/vendor/wasm-bindgen-futures/src/queue.rs b/vendor/wasm-bindgen-futures/src/queue.rs
new file mode 100644
index 000000000..9a78571cd
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/queue.rs
@@ -0,0 +1,91 @@
+use js_sys::Promise;
+use std::cell::{Cell, RefCell};
+use std::collections::VecDeque;
+use std::rc::Rc;
+use wasm_bindgen::prelude::*;
+
+struct QueueState {
+ // The queue of Tasks which are to be run in order. In practice this is all the
+ // synchronous work of futures, and each `Task` represents calling `poll` on
+ // a future "at the right time".
+ tasks: RefCell<VecDeque<Rc<crate::task::Task>>>,
+
+ // This flag indicates whether we've scheduled `run_all` to run in the future.
+ // This is used to ensure that it's only scheduled once.
+ is_scheduled: Cell<bool>,
+}
+
+impl QueueState {
+ fn run_all(&self) {
+ // "consume" the schedule
+ let _was_scheduled = self.is_scheduled.replace(false);
+ debug_assert!(_was_scheduled);
+
+ // Stop when all tasks that have been scheduled before this tick have been run.
+ // Tasks that are scheduled while running tasks will run on the next tick.
+ let mut task_count_left = self.tasks.borrow().len();
+ while task_count_left > 0 {
+ task_count_left -= 1;
+ let task = match self.tasks.borrow_mut().pop_front() {
+ Some(task) => task,
+ None => break,
+ };
+ task.run();
+ }
+
+ // All of the Tasks have been run, so it's now possible to schedule the
+ // next tick again
+ }
+}
+
+pub(crate) struct Queue {
+ state: Rc<QueueState>,
+ promise: Promise,
+ closure: Closure<dyn FnMut(JsValue)>,
+}
+
+impl Queue {
+ // Schedule a task to run on the next tick
+ pub(crate) fn schedule_task(&self, task: Rc<crate::task::Task>) {
+ self.state.tasks.borrow_mut().push_back(task);
+ // Note that we currently use a promise and a closure to do this, but
+ // eventually we should probably use something like `queueMicrotask`:
+ // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/queueMicrotask
+ if !self.state.is_scheduled.replace(true) {
+ let _ = self.promise.then(&self.closure);
+ }
+ }
+ // Append a task to the currently running queue, or schedule it
+ pub(crate) fn push_task(&self, task: Rc<crate::task::Task>) {
+ // It would make sense to run this task on the same tick. For now, we
+ // make the simplifying choice of always scheduling tasks for a future tick.
+ self.schedule_task(task)
+ }
+}
+
+impl Queue {
+ fn new() -> Self {
+ let state = Rc::new(QueueState {
+ is_scheduled: Cell::new(false),
+ tasks: RefCell::new(VecDeque::new()),
+ });
+
+ Self {
+ promise: Promise::resolve(&JsValue::undefined()),
+
+ closure: {
+ let state = Rc::clone(&state);
+
+ // This closure will only be called on the next microtask event
+ // tick
+ Closure::new(move |_| state.run_all())
+ },
+
+ state,
+ }
+ }
+}
+
+thread_local! {
+ pub(crate) static QUEUE: Queue = Queue::new();
+}
diff --git a/vendor/wasm-bindgen-futures/src/stream.rs b/vendor/wasm-bindgen-futures/src/stream.rs
new file mode 100644
index 000000000..fe35d81c7
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/stream.rs
@@ -0,0 +1,81 @@
+//! Converting JavaScript `AsyncIterator`s to Rust `Stream`s.
+//!
+//! Analogous to the promise to future conversion, this module allows
+//! turning objects implementing the async iterator protocol into `Stream`s
+//! that produce values that can be awaited from.
+//!
+
+use crate::JsFuture;
+use core::future::Future;
+use core::pin::Pin;
+use core::task::{Context, Poll};
+use futures_core::stream::Stream;
+use js_sys::{AsyncIterator, IteratorNext};
+use wasm_bindgen::prelude::*;
+
+/// A `Stream` that yields values from an underlying `AsyncIterator`.
+pub struct JsStream {
+ iter: AsyncIterator,
+ next: Option<JsFuture>,
+ done: bool,
+}
+
+impl JsStream {
+ fn next_future(&self) -> Result<JsFuture, JsValue> {
+ self.iter.next().map(JsFuture::from)
+ }
+}
+
+impl From<AsyncIterator> for JsStream {
+ fn from(iter: AsyncIterator) -> Self {
+ JsStream {
+ iter,
+ next: None,
+ done: false,
+ }
+ }
+}
+
+impl Stream for JsStream {
+ type Item = Result<JsValue, JsValue>;
+
+ fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
+ if self.done {
+ return Poll::Ready(None);
+ }
+
+ let future = match self.next.as_mut() {
+ Some(val) => val,
+ None => match self.next_future() {
+ Ok(val) => {
+ self.next = Some(val);
+ self.next.as_mut().unwrap()
+ }
+ Err(e) => {
+ self.done = true;
+ return Poll::Ready(Some(Err(e)));
+ }
+ },
+ };
+
+ match Pin::new(future).poll(cx) {
+ Poll::Ready(res) => match res {
+ Ok(iter_next) => {
+ let next = iter_next.unchecked_into::<IteratorNext>();
+ if next.done() {
+ self.done = true;
+ Poll::Ready(None)
+ } else {
+ self.next.take();
+ Poll::Ready(Some(Ok(next.value())))
+ }
+ }
+ Err(e) => {
+ self.done = true;
+ Poll::Ready(Some(Err(e)))
+ }
+ },
+ Poll::Pending => Poll::Pending,
+ }
+ }
+}
diff --git a/vendor/wasm-bindgen-futures/src/task/multithread.rs b/vendor/wasm-bindgen-futures/src/task/multithread.rs
new file mode 100644
index 000000000..6cfdfcb54
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/task/multithread.rs
@@ -0,0 +1,201 @@
+use std::cell::RefCell;
+use std::future::Future;
+use std::mem::ManuallyDrop;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::sync::atomic::AtomicI32;
+use std::sync::atomic::Ordering::SeqCst;
+use std::sync::Arc;
+use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+use wasm_bindgen::prelude::*;
+
+const SLEEPING: i32 = 0;
+const AWAKE: i32 = 1;
+
+struct AtomicWaker {
+ state: AtomicI32,
+}
+
+impl AtomicWaker {
+ fn new() -> Arc<Self> {
+ Arc::new(Self {
+ state: AtomicI32::new(AWAKE),
+ })
+ }
+
+ fn wake_by_ref(&self) {
+ // If we're already AWAKE then we previously notified and there's
+ // nothing to do...
+ match self.state.swap(AWAKE, SeqCst) {
+ AWAKE => return,
+ other => debug_assert_eq!(other, SLEEPING),
+ }
+
+ // ... otherwise we execute the native `notify` instruction to wake up
+ // the corresponding `waitAsync` that was waiting for the transition
+ // from SLEEPING to AWAKE.
+ unsafe {
+ core::arch::wasm32::memory_atomic_notify(
+ &self.state as *const AtomicI32 as *mut i32,
+ 1, // Number of threads to notify
+ );
+ }
+ }
+
+ /// Same as the singlethread module, this creates a standard library
+ /// `RawWaker`. We could use `futures_util::task::ArcWake` but it's small
+ /// enough that we just inline it for now.
+ unsafe fn into_raw_waker(this: Arc<Self>) -> RawWaker {
+ unsafe fn raw_clone(ptr: *const ()) -> RawWaker {
+ let ptr = ManuallyDrop::new(Arc::from_raw(ptr as *const AtomicWaker));
+ AtomicWaker::into_raw_waker((*ptr).clone())
+ }
+
+ unsafe fn raw_wake(ptr: *const ()) {
+ let ptr = Arc::from_raw(ptr as *const AtomicWaker);
+ AtomicWaker::wake_by_ref(&ptr);
+ }
+
+ unsafe fn raw_wake_by_ref(ptr: *const ()) {
+ let ptr = ManuallyDrop::new(Arc::from_raw(ptr as *const AtomicWaker));
+ AtomicWaker::wake_by_ref(&ptr);
+ }
+
+ unsafe fn raw_drop(ptr: *const ()) {
+ drop(Arc::from_raw(ptr as *const AtomicWaker));
+ }
+
+ const VTABLE: RawWakerVTable =
+ RawWakerVTable::new(raw_clone, raw_wake, raw_wake_by_ref, raw_drop);
+
+ RawWaker::new(Arc::into_raw(this) as *const (), &VTABLE)
+ }
+}
+
+struct Inner {
+ future: Pin<Box<dyn Future<Output = ()> + 'static>>,
+ closure: Closure<dyn FnMut(JsValue)>,
+}
+
+pub(crate) struct Task {
+ atomic: Arc<AtomicWaker>,
+ waker: Waker,
+ // See `singlethread.rs` for why this is an internal `Option`.
+ inner: RefCell<Option<Inner>>,
+}
+
+impl Task {
+ pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
+ let atomic = AtomicWaker::new();
+ let waker = unsafe { Waker::from_raw(AtomicWaker::into_raw_waker(atomic.clone())) };
+ let this = Rc::new(Task {
+ atomic,
+ waker,
+ inner: RefCell::new(None),
+ });
+
+ let closure = {
+ let this = Rc::clone(&this);
+ Closure::new(move |_| this.run())
+ };
+ *this.inner.borrow_mut() = Some(Inner { future, closure });
+
+ // Queue up the Future's work to happen on the next microtask tick.
+ crate::queue::QUEUE.with(move |queue| queue.schedule_task(this));
+ }
+
+ pub(crate) fn run(&self) {
+ let mut borrow = self.inner.borrow_mut();
+
+ // Same as `singlethread.rs`, handle spurious wakeups happening after we
+ // finished.
+ let inner = match borrow.as_mut() {
+ Some(inner) => inner,
+ None => return,
+ };
+
+ loop {
+ // Also the same as `singlethread.rs`, flag ourselves as ready to
+ // receive a notification.
+ let prev = self.atomic.state.swap(SLEEPING, SeqCst);
+ debug_assert_eq!(prev, AWAKE);
+
+ let poll = {
+ let mut cx = Context::from_waker(&self.waker);
+ inner.future.as_mut().poll(&mut cx)
+ };
+
+ match poll {
+ // Same as `singlethread.rs` (noticing a pattern?) clean up
+ // resources associated with the future ASAP.
+ Poll::Ready(()) => {
+ *borrow = None;
+ }
+
+ // Unlike `singlethread.rs` we are responsible for ensuring there's
+ // a closure to handle the notification that a Future is ready. In
+ // the single-threaded case the notification itself enqueues work,
+ // but in the multithreaded case we don't know what thread a
+ // notification comes from so we need to ensure the current running
+ // thread is the one that enqueues the work. To do that we execute
+ // `Atomics.waitAsync`, creating a local Promise on our own thread
+ // which will resolve once `Atomics.notify` is called.
+ //
+ // We could be in one of two states as we execute this:
+ //
+ // * `SLEEPING` - we'll get notified via `Atomics.notify`
+ // and then this Promise will resolve.
+ //
+ // * `AWAKE` - the Promise will immediately be resolved and
+ // we'll execute the work on the next microtask queue.
+ Poll::Pending => {
+ match wait_async(&self.atomic.state, SLEEPING) {
+ Some(promise) => drop(promise.then(&inner.closure)),
+ // our state has already changed so we can just do the work
+ // again inline.
+ None => continue,
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+fn wait_async(ptr: &AtomicI32, current_value: i32) -> Option<js_sys::Promise> {
+ // If `Atomics.waitAsync` isn't defined then we use our fallback, otherwise
+ // we use the native function.
+ return if Atomics::get_wait_async().is_undefined() {
+ Some(crate::task::wait_async_polyfill::wait_async(
+ ptr,
+ current_value,
+ ))
+ } else {
+ let mem = wasm_bindgen::memory().unchecked_into::<js_sys::WebAssembly::Memory>();
+ let array = js_sys::Int32Array::new(&mem.buffer());
+ let result = Atomics::wait_async(&array, ptr as *const AtomicI32 as i32 / 4, current_value);
+ if result.async_() {
+ Some(result.value())
+ } else {
+ None
+ }
+ };
+
+ #[wasm_bindgen]
+ extern "C" {
+ type Atomics;
+ type WaitAsyncResult;
+
+ #[wasm_bindgen(static_method_of = Atomics, js_name = waitAsync)]
+ fn wait_async(buf: &js_sys::Int32Array, index: i32, value: i32) -> WaitAsyncResult;
+
+ #[wasm_bindgen(static_method_of = Atomics, js_name = waitAsync, getter)]
+ fn get_wait_async() -> JsValue;
+
+ #[wasm_bindgen(method, getter, structural, js_name = async)]
+ fn async_(this: &WaitAsyncResult) -> bool;
+
+ #[wasm_bindgen(method, getter, structural)]
+ fn value(this: &WaitAsyncResult) -> js_sys::Promise;
+ }
+}
diff --git a/vendor/wasm-bindgen-futures/src/task/singlethread.rs b/vendor/wasm-bindgen-futures/src/task/singlethread.rs
new file mode 100644
index 000000000..570cd6fcf
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/task/singlethread.rs
@@ -0,0 +1,113 @@
+use std::cell::{Cell, RefCell};
+use std::future::Future;
+use std::mem::ManuallyDrop;
+use std::pin::Pin;
+use std::rc::Rc;
+use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
+
+struct Inner {
+ future: Pin<Box<dyn Future<Output = ()> + 'static>>,
+ waker: Waker,
+}
+
+pub(crate) struct Task {
+ // The actual Future that we're executing as part of this task.
+ //
+ // This is an Option so that the Future can be immediately dropped when it's
+ // finished
+ inner: RefCell<Option<Inner>>,
+
+ // This is used to ensure that the Task will only be queued once
+ is_queued: Cell<bool>,
+}
+
+impl Task {
+ pub(crate) fn spawn(future: Pin<Box<dyn Future<Output = ()> + 'static>>) {
+ let this = Rc::new(Self {
+ inner: RefCell::new(None),
+ is_queued: Cell::new(true),
+ });
+
+ let waker = unsafe { Waker::from_raw(Task::into_raw_waker(Rc::clone(&this))) };
+
+ *this.inner.borrow_mut() = Some(Inner { future, waker });
+
+ crate::queue::QUEUE.with(|queue| queue.schedule_task(this));
+ }
+
+ fn wake_by_ref(this: &Rc<Self>) {
+ // If we've already been placed on the run queue then there's no need to
+ // requeue ourselves since we're going to run at some point in the
+ // future anyway.
+ if this.is_queued.replace(true) {
+ return;
+ }
+
+ crate::queue::QUEUE.with(|queue| {
+ queue.push_task(Rc::clone(this));
+ });
+ }
+
+ /// Creates a standard library `RawWaker` from an `Rc` of ourselves.
+ ///
+ /// Note that in general this is wildly unsafe because everything with
+ /// Futures requires `Sync` + `Send` with regard to Wakers. For wasm,
+ /// however, everything is guaranteed to be singlethreaded (since we're
+ /// compiled without the `atomics` feature) so we "safely lie" and say our
+ /// `Rc` pointer is good enough.
+ unsafe fn into_raw_waker(this: Rc<Self>) -> RawWaker {
+ unsafe fn raw_clone(ptr: *const ()) -> RawWaker {
+ let ptr = ManuallyDrop::new(Rc::from_raw(ptr as *const Task));
+ Task::into_raw_waker((*ptr).clone())
+ }
+
+ unsafe fn raw_wake(ptr: *const ()) {
+ let ptr = Rc::from_raw(ptr as *const Task);
+ Task::wake_by_ref(&ptr);
+ }
+
+ unsafe fn raw_wake_by_ref(ptr: *const ()) {
+ let ptr = ManuallyDrop::new(Rc::from_raw(ptr as *const Task));
+ Task::wake_by_ref(&ptr);
+ }
+
+ unsafe fn raw_drop(ptr: *const ()) {
+ drop(Rc::from_raw(ptr as *const Task));
+ }
+
+ const VTABLE: RawWakerVTable =
+ RawWakerVTable::new(raw_clone, raw_wake, raw_wake_by_ref, raw_drop);
+
+ RawWaker::new(Rc::into_raw(this) as *const (), &VTABLE)
+ }
+
+ pub(crate) fn run(&self) {
+ let mut borrow = self.inner.borrow_mut();
+
+ // Wakeups can come in after a Future has finished and been destroyed,
+ // so handle this gracefully by just ignoring the request to run.
+ let inner = match borrow.as_mut() {
+ Some(inner) => inner,
+ None => return,
+ };
+
+ // Ensure that if poll calls `waker.wake()` we can get enqueued back on
+ // the run queue.
+ self.is_queued.set(false);
+
+ let poll = {
+ let mut cx = Context::from_waker(&inner.waker);
+ inner.future.as_mut().poll(&mut cx)
+ };
+
+ // If a future has finished (`Ready`) then clean up resources associated
+ // with the future ASAP. This ensures that we don't keep anything extra
+ // alive in-memory by accident. Our own struct, `Rc<Task>` won't
+ // actually go away until all wakers referencing us go away, which may
+ // take quite some time, so ensure that the heaviest of resources are
+ // released early.
+ if let Poll::Ready(_) = poll {
+ *borrow = None;
+ }
+ }
+}
diff --git a/vendor/wasm-bindgen-futures/src/task/wait_async_polyfill.rs b/vendor/wasm-bindgen-futures/src/task/wait_async_polyfill.rs
new file mode 100644
index 000000000..68332d91a
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/task/wait_async_polyfill.rs
@@ -0,0 +1,91 @@
+//!
+//! The polyfill was kindly borrowed from https://github.com/tc39/proposal-atomics-wait-async
+//! and ported to Rust
+//!
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Author: Lars T Hansen, lhansen@mozilla.com
+ */
+
+/* Polyfill for Atomics.waitAsync() for web browsers.
+ *
+ * Any kind of agent that is able to create a new Worker can use this polyfill.
+ *
+ * Load this file in all agents that will use Atomics.waitAsync.
+ *
+ * Agents that don't call Atomics.waitAsync need do nothing special.
+ *
+ * Any kind of agent can wake another agent that is sleeping in
+ * Atomics.waitAsync by just calling Atomics.wake for the location being slept
+ * on, as normal.
+ *
+ * The implementation is not completely faithful to the proposed semantics: in
+ * the case where an agent first asyncWaits and then waits on the same location:
+ * when it is woken, the two waits will be woken in order, while in the real
+ * semantics, the sync wait will be woken first.
+ *
+ * In this polyfill Atomics.waitAsync is not very fast.
+ */
+
+/* Implementation:
+ *
+ * For every wait we fork off a Worker to perform the wait. Workers are reused
+ * when possible. The worker communicates with its parent using postMessage.
+ */
+
+use js_sys::{Array, Promise};
+use std::cell::RefCell;
+use std::sync::atomic::AtomicI32;
+use wasm_bindgen::prelude::*;
+use web_sys::{MessageEvent, Worker};
+
+thread_local! {
+ static HELPERS: RefCell<Vec<Worker>> = RefCell::new(vec![]);
+}
+
+fn alloc_helper() -> Worker {
+ HELPERS.with(|helpers| {
+ if let Some(helper) = helpers.borrow_mut().pop() {
+ return helper;
+ }
+
+ let worker_url = wasm_bindgen::link_to!(module = "/src/task/worker.js");
+ Worker::new(&worker_url).unwrap_or_else(|js| wasm_bindgen::throw_val(js))
+ })
+}
+
+fn free_helper(helper: Worker) {
+ HELPERS.with(move |helpers| {
+ let mut helpers = helpers.borrow_mut();
+ helpers.push(helper.clone());
+ helpers.truncate(10); // random arbitrary limit chosen here
+ });
+}
+
+pub fn wait_async(ptr: &AtomicI32, value: i32) -> Promise {
+ Promise::new(&mut |resolve, _reject| {
+ let helper = alloc_helper();
+ let helper_ref = helper.clone();
+
+ let onmessage_callback = Closure::once_into_js(move |e: MessageEvent| {
+ // Our helper is done waiting so it's available to wait on a
+ // different location, so return it to the free list.
+ free_helper(helper_ref);
+ drop(resolve.call1(&JsValue::NULL, &e.data()));
+ });
+ helper.set_onmessage(Some(onmessage_callback.as_ref().unchecked_ref()));
+
+ let data = Array::of3(
+ &wasm_bindgen::memory(),
+ &JsValue::from(ptr as *const AtomicI32 as i32 / 4),
+ &JsValue::from(value),
+ );
+
+ helper
+ .post_message(&data)
+ .unwrap_or_else(|js| wasm_bindgen::throw_val(js));
+ })
+}
diff --git a/vendor/wasm-bindgen-futures/src/task/worker.js b/vendor/wasm-bindgen-futures/src/task/worker.js
new file mode 100644
index 000000000..d25dab660
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/src/task/worker.js
@@ -0,0 +1,6 @@
+onmessage = function (ev) {
+ let [ia, index, value] = ev.data;
+ ia = new Int32Array(ia.buffer);
+ let result = Atomics.wait(ia, index, value);
+ postMessage(result);
+};
diff --git a/vendor/wasm-bindgen-futures/tests/tests.rs b/vendor/wasm-bindgen-futures/tests/tests.rs
new file mode 100644
index 000000000..6a950f7c8
--- /dev/null
+++ b/vendor/wasm-bindgen-futures/tests/tests.rs
@@ -0,0 +1,157 @@
+#![cfg(target_arch = "wasm32")]
+
+wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
+
+use futures_channel::oneshot;
+use js_sys::Promise;
+use std::ops::FnMut;
+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_nested() {
+ let (ta, mut ra) = oneshot::channel::<u32>();
+ let (ts, rs) = oneshot::channel::<u32>();
+ let (tx, rx) = oneshot::channel::<u32>();
+ // The order in which the various promises and tasks run is important!
+ // We want, on different ticks each, the following things to happen
+ // 1. A promise resolves, off of which we can spawn our inbetween assertion
+ // 2. The outer task runs, spawns in the inner task, and the inbetween promise, then yields
+ // 3. The inbetween promise runs and asserts that the inner task hasn't run
+ // 4. The inner task runs
+ // This depends crucially on two facts:
+ // - JsFuture schedules on ticks independently from tasks
+ // - The order of ticks is the same as the code flow
+ let promise = Promise::resolve(&JsValue::null());
+
+ spawn_local(async move {
+ // Create a closure that runs in between the two ticks and
+ // assert that the inner task hasn't run yet
+ let inbetween = Closure::wrap(Box::new(move |_| {
+ assert_eq!(
+ ra.try_recv().unwrap(),
+ None,
+ "Nested task should not have run yet"
+ );
+ }) as Box<dyn FnMut(JsValue)>);
+ let inbetween = promise.then(&inbetween);
+ spawn_local(async {
+ ta.send(0xdead).unwrap();
+ ts.send(0xbeaf).unwrap();
+ });
+ JsFuture::from(inbetween).await.unwrap();
+ assert_eq!(
+ rs.await.unwrap(),
+ 0xbeaf,
+ "Nested task should run eventually"
+ );
+ 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();
+}
+
+#[cfg(feature = "futures-core-03-stream")]
+#[wasm_bindgen_test]
+async fn can_use_an_async_iterable_as_stream() {
+ use futures_lite::stream::StreamExt;
+ use wasm_bindgen_futures::stream::JsStream;
+
+ let async_iter = js_sys::Function::new_no_args(
+ "return async function*() {
+ yield 42;
+ yield 24;
+ }()",
+ )
+ .call0(&JsValue::undefined())
+ .unwrap()
+ .unchecked_into::<js_sys::AsyncIterator>();
+
+ let mut stream = JsStream::from(async_iter);
+ assert_eq!(stream.next().await, Some(Ok(JsValue::from(42))));
+ assert_eq!(stream.next().await, Some(Ok(JsValue::from(24))));
+ assert_eq!(stream.next().await, None);
+}