wasm-bindgen-0.2.99/.cargo_vcs_info.json0000644000000001360000000000100135100ustar { "git": { "sha1": "04ca6f34ae52454910c7c4fa15c7bfde0126db79" }, "path_in_vcs": "" }wasm-bindgen-0.2.99/Cargo.toml0000644000000044530000000000100115140ustar # 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 = "2021" rust-version = "1.57" name = "wasm-bindgen" version = "0.2.99" authors = ["The wasm-bindgen Developers"] build = "build.rs" include = [ "/build.rs", "/LICENSE-*", "/src", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = """ Easy support for interacting between JS and Rust. """ homepage = "https://rustwasm.github.io/" documentation = "https://docs.rs/wasm-bindgen" readme = "README.md" categories = ["wasm"] license = "MIT OR Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen" [package.metadata.docs.rs] features = ["serde-serialize"] [lib] name = "wasm_bindgen" path = "src/lib.rs" test = false [dependencies.cfg-if] version = "1.0.0" [dependencies.once_cell] version = "1.12" default-features = false [dependencies.serde] version = "1.0" optional = true [dependencies.serde_json] version = "1.0" optional = true [dependencies.wasm-bindgen-macro] version = "=0.2.99" default-features = false [dev-dependencies] [features] default = [ "spans", "std", ] enable-interning = ["std"] gg-alloc = [] serde-serialize = [ "serde", "serde_json", "std", ] spans = ["wasm-bindgen-macro/spans"] std = [ "wasm-bindgen-macro/std", "once_cell/std", ] strict-macro = ["wasm-bindgen-macro/strict-macro"] xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_generated_code"] [target.'cfg(target_arch = "wasm32")'.dev-dependencies.paste] version = "1" [target.'cfg(target_arch = "wasm32")'.dev-dependencies.serde_derive] version = "1.0" [lints.clippy] large_enum_variant = "allow" new_without_default = "allow" overly_complex_bool_expr = "allow" too_many_arguments = "allow" type_complexity = "allow" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = ["cfg(wasm_bindgen_unstable_test_coverage)"] wasm-bindgen-0.2.99/Cargo.toml.orig000064400000000000000000000072741046102023000152010ustar 00000000000000[package] authors = ["The wasm-bindgen Developers"] categories = ["wasm"] description = """ Easy support for interacting between JS and Rust. """ documentation = "https://docs.rs/wasm-bindgen" edition = "2021" homepage = "https://rustwasm.github.io/" include = ["/build.rs", "/LICENSE-*", "/src"] license = "MIT OR Apache-2.0" name = "wasm-bindgen" readme = "README.md" repository = "https://github.com/rustwasm/wasm-bindgen" rust-version = "1.57" version = "0.2.99" [package.metadata.docs.rs] features = ["serde-serialize"] [lib] test = false [features] default = ["spans", "std"] enable-interning = ["std"] serde-serialize = ["serde", "serde_json", "std"] spans = ["wasm-bindgen-macro/spans"] std = ["wasm-bindgen-macro/std", "once_cell/std"] # Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on # all unused attributes strict-macro = ["wasm-bindgen-macro/strict-macro"] # Enables gg-alloc as system allocator when using wasm-bindgen-test to check that large pointers # are handled correctly gg-alloc = ["wasm-bindgen-test/gg-alloc"] # This is only for debugging wasm-bindgen! No stability guarantees, so enable # this at your own peril! xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_generated_code"] [dependencies] cfg-if = "1.0.0" once_cell = { version = "1.12", default-features = false } serde = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true } wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.99", default-features = false } [dev-dependencies] wasm-bindgen-test = { path = 'crates/test' } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] js-sys = { path = 'crates/js-sys' } paste = "1" serde_derive = "1.0" wasm-bindgen-futures = { path = 'crates/futures' } wasm-bindgen-test-crate-a = { path = 'tests/crates/a' } wasm-bindgen-test-crate-b = { path = 'tests/crates/b' } [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] } [lints.clippy] large_enum_variant = "allow" new_without_default = "allow" overly_complex_bool_expr = "allow" too_many_arguments = "allow" type_complexity = "allow" [workspace.lints.clippy] large_enum_variant = "allow" new_without_default = "allow" overly_complex_bool_expr = "allow" too_many_arguments = "allow" type_complexity = "allow" [workspace] exclude = ["crates/msrv/resolver", "crates/msrv/lib", "crates/msrv/cli"] members = [ "benchmarks", "crates/cli", "crates/js-sys", "crates/test", "crates/test/sample", "crates/example-tests", "crates/typescript-tests", "crates/web-sys", "crates/webidl", "crates/webidl-tests", "examples/add", "examples/canvas", "examples/char", "examples/closures", "examples/console_log", "examples/deno", "examples/dom", "examples/duck-typed-interfaces", "examples/explicit-resource-management", "examples/fetch", "examples/guide-supported-types-examples", "examples/hello_world", "examples/import_js/crate", "examples/julia_set", "examples/paint", "examples/performance", "examples/raytrace-parallel", "examples/request-animation-frame", "examples/todomvc", "examples/wasm-audio-worklet", "examples/wasm-in-wasm", "examples/wasm-in-wasm-imports", "examples/wasm-in-web-worker", "examples/weather_report", "examples/webaudio", "examples/webgl", "examples/webrtc_datachannel", "examples/websockets", "examples/webxr", "examples/without-a-bundler", "examples/without-a-bundler-no-modules", "examples/synchronous-instantiation", "tests/no-std", ] resolver = "2" [patch.crates-io] js-sys = { path = 'crates/js-sys' } wasm-bindgen = { path = '.' } wasm-bindgen-futures = { path = 'crates/futures' } web-sys = { path = 'crates/web-sys' } wasm-bindgen-0.2.99/LICENSE-APACHE000064400000000000000000000251371046102023000142340ustar 00000000000000 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. wasm-bindgen-0.2.99/LICENSE-MIT000064400000000000000000000020411046102023000137310ustar 00000000000000Copyright (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. wasm-bindgen-0.2.99/README.md000064400000000000000000000113771046102023000135700ustar 00000000000000

wasm-bindgen

Facilitating high-level interactions between Wasm modules and JavaScript.

Build Status Crates.io version Download docs.rs docs

Guide (main branch) | API Docs | Contributing | Chat

Built with 🦀🕸 by The Rust and WebAssembly Working Group
## Install `wasm-bindgen-cli` You can install it using `cargo install`: ``` cargo install wasm-bindgen-cli ``` Or, you can download it from the [release page](https://github.com/rustwasm/wasm-bindgen/releases). If you have [`cargo-binstall`](https://crates.io/crates/cargo-binstall) installed, then you can install the pre-built artifacts by running: ``` cargo binstall wasm-bindgen-cli ``` ## Example Import JavaScript things into Rust and export Rust things to JavaScript. ```rust use wasm_bindgen::prelude::*; // Import the `window.alert` function from the Web. #[wasm_bindgen] extern "C" { fn alert(s: &str); } // Export a `greet` function from Rust to JavaScript, that alerts a // hello message. #[wasm_bindgen] pub fn greet(name: &str) { alert(&format!("Hello, {}!", name)); } ``` Use exported Rust things from JavaScript with ECMAScript modules! ```js import { greet } from "./hello_world"; greet("World!"); ``` ## Features * **Lightweight.** Only pay for what you use. `wasm-bindgen` only generates bindings and glue for the JavaScript imports you actually use and Rust functionality that you export. For example, importing and using the `document.querySelector` method doesn't cause `Node.prototype.appendChild` or `window.alert` to be included in the bindings as well. * **ECMAScript modules.** Just import WebAssembly modules the same way you would import JavaScript modules. Future compatible with [WebAssembly modules and ECMAScript modules integration][wasm-es-modules]. * **Designed with the ["Web IDL bindings" proposal][webidl-bindings] in mind.** Eventually, there won't be any JavaScript shims between Rust-generated wasm functions and native DOM methods. Because the Wasm functions are statically type checked, some of those native methods' dynamic type checks should become unnecessary, promising to unlock even-faster-than-JavaScript DOM access. [wasm-es-modules]: https://github.com/WebAssembly/esm-integration [webidl-bindings]: https://github.com/WebAssembly/proposals/issues/8 ## Guide [**📚 Read the `wasm-bindgen` guide here! 📚**](https://rustwasm.github.io/docs/wasm-bindgen/) You can find general documentation about using Rust and WebAssembly together [here](https://rustwasm.github.io/docs). ## API Docs - [wasm-bindgen](https://docs.rs/wasm-bindgen) - [js-sys](https://docs.rs/js-sys) - [web-sys](https://docs.rs/web-sys) - [wasm-bindgen-futures](https://docs.rs/wasm-bindgen-futures) ## MSRV Policy Libraries that are released on [crates.io](https://crates.io) have a MSRV of v1.57. Changes to the MSRV will be accompanied by a minor version bump. CLI tools and their corresponding support libraries have a MSRV of v1.76. Changes to the MSRV will be accompanied by a patch version bump. ## License This project is licensed under either of * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ## Contribution **[See the "Contributing" section of the guide for information on hacking on `wasm-bindgen`!][contributing]** Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. [contributing]: https://rustwasm.github.io/docs/wasm-bindgen/contributing/index.html wasm-bindgen-0.2.99/build.rs000064400000000000000000000002121046102023000137400ustar 00000000000000// Empty `build.rs` so that `[package] links = ...` works in `Cargo.toml`. fn main() { println!("cargo:rerun-if-changed=build.rs"); } wasm-bindgen-0.2.99/src/cache/intern.rs000064400000000000000000000061051046102023000160010ustar 00000000000000use cfg_if::cfg_if; cfg_if! { if #[cfg(feature = "enable-interning")] { use std::thread_local; use std::string::String; use std::borrow::ToOwned; use std::cell::RefCell; use std::collections::HashMap; use crate::JsValue; struct Cache { entries: RefCell>, } thread_local! { static CACHE: Cache = Cache { entries: RefCell::new(HashMap::new()), }; } /// This returns the raw index of the cached JsValue, so you must take care /// so that you don't use it after it is freed. pub(crate) fn unsafe_get_str(s: &str) -> Option { CACHE.with(|cache| { let cache = cache.entries.borrow(); cache.get(s).map(|x| x.idx) }) } fn intern_str(key: &str) { CACHE.with(|cache| { let mut cache = cache.entries.borrow_mut(); // Can't use `entry` because `entry` requires a `String` if !cache.contains_key(key) { cache.insert(key.to_owned(), JsValue::from(key)); } }) } fn unintern_str(key: &str) { CACHE.with(|cache| { let mut cache = cache.entries.borrow_mut(); cache.remove(key); }) } } } /// Interns Rust strings so that it's much faster to send them to JS. /// /// Sending strings from Rust to JS is slow, because it has to do a full `O(n)` /// copy and *also* encode from UTF-8 to UTF-16. This must be done every single /// time a string is sent to JS. /// /// If you are sending the same string multiple times, you can call this `intern` /// function, which simply returns its argument unchanged: /// /// ```rust /// # use wasm_bindgen::intern; /// intern("foo") // returns "foo" /// # ; /// ``` /// /// However, if you enable the `"enable-interning"` feature for wasm-bindgen, /// then it will add the string into an internal cache. /// /// When you send that cached string to JS, it will look it up in the cache, /// which completely avoids the `O(n)` copy and encoding. This has a significant /// speed boost (as high as 783%)! /// /// However, there is a small cost to this caching, so you shouldn't cache every /// string. Only cache strings which have a high likelihood of being sent /// to JS multiple times. /// /// Also, keep in mind that this function is a *performance hint*: it's not /// *guaranteed* that the string will be cached, and the caching strategy /// might change at any time, so don't rely upon it. #[inline] pub fn intern(s: &str) -> &str { #[cfg(feature = "enable-interning")] intern_str(s); s } /// Removes a Rust string from the intern cache. /// /// This does the opposite of the [`intern`](fn.intern.html) function. /// /// If the [`intern`](fn.intern.html) function is called again then it will re-intern the string. #[allow(unused_variables)] #[inline] pub fn unintern(s: &str) { #[cfg(feature = "enable-interning")] unintern_str(s); } wasm-bindgen-0.2.99/src/cache/mod.rs000064400000000000000000000000201046102023000152470ustar 00000000000000pub mod intern; wasm-bindgen-0.2.99/src/cast.rs000064400000000000000000000140141046102023000143670ustar 00000000000000use crate::{describe::WasmDescribe, JsValue}; /// A trait for checked and unchecked casting between JS types. /// /// Specified [in an RFC][rfc] this trait is intended to provide support for /// casting JS values between different types of one another. In JS there aren't /// many static types but we've ascribed JS values with static types in Rust, /// yet they often need to be switched to other types temporarily! This trait /// provides both checked and unchecked casting into various kinds of values. /// /// This trait is automatically implemented for any type imported in a /// `#[wasm_bindgen]` `extern` block. /// /// [rfc]: https://github.com/rustwasm/rfcs/blob/master/text/002-wasm-bindgen-inheritance-casting.md pub trait JsCast where Self: AsRef + Into, { /// Test whether this JS value has a type `T`. /// /// This method will dynamically check to see if this JS object can be /// casted to the JS object of type `T`. Usually this uses the `instanceof` /// operator. This also works with primitive types like /// booleans/strings/numbers as well as cross-realm object like `Array` /// which can originate from other iframes. /// /// In general this is intended to be a more robust version of /// `is_instance_of`, but if you want strictly the `instanceof` operator /// it's recommended to use that instead. fn has_type(&self) -> bool where T: JsCast, { T::is_type_of(self.as_ref()) } /// Performs a dynamic cast (checked at runtime) of this value into the /// target type `T`. /// /// This method will return `Err(self)` if `self.has_type::()` /// returns `false`, and otherwise it will return `Ok(T)` manufactured with /// an unchecked cast (verified correct via the `has_type` operation). fn dyn_into(self) -> Result where T: JsCast, { if self.has_type::() { Ok(self.unchecked_into()) } else { Err(self) } } /// Performs a dynamic cast (checked at runtime) of this value into the /// target type `T`. /// /// This method will return `None` if `self.has_type::()` /// returns `false`, and otherwise it will return `Some(&T)` manufactured /// with an unchecked cast (verified correct via the `has_type` operation). fn dyn_ref(&self) -> Option<&T> where T: JsCast, { if self.has_type::() { Some(self.unchecked_ref()) } else { None } } /// Performs a zero-cost unchecked cast into the specified type. /// /// This method will convert the `self` value to the type `T`, where both /// `self` and `T` are simple wrappers around `JsValue`. This method **does /// not check whether `self` is an instance of `T`**. If used incorrectly /// then this method may cause runtime exceptions in both Rust and JS, this /// should be used with caution. fn unchecked_into(self) -> T where T: JsCast, { T::unchecked_from_js(self.into()) } /// Performs a zero-cost unchecked cast into a reference to the specified /// type. /// /// This method will convert the `self` value to the type `T`, where both /// `self` and `T` are simple wrappers around `JsValue`. This method **does /// not check whether `self` is an instance of `T`**. If used incorrectly /// then this method may cause runtime exceptions in both Rust and JS, this /// should be used with caution. /// /// This method, unlike `unchecked_into`, does not consume ownership of /// `self` and instead works over a shared reference. fn unchecked_ref(&self) -> &T where T: JsCast, { T::unchecked_from_js_ref(self.as_ref()) } /// Test whether this JS value is an instance of the type `T`. /// /// This method performs a dynamic check (at runtime) using the JS /// `instanceof` operator. This method returns `self instanceof T`. /// /// Note that `instanceof` does not always work with primitive values or /// across different realms (e.g. iframes). If you're not sure whether you /// specifically need only `instanceof` it's recommended to use `has_type` /// instead. fn is_instance_of(&self) -> bool where T: JsCast, { T::instanceof(self.as_ref()) } /// Performs a dynamic `instanceof` check to see whether the `JsValue` /// provided is an instance of this type. /// /// This is intended to be an internal implementation detail, you likely /// won't need to call this. It's generally called through the /// `is_instance_of` method instead. fn instanceof(val: &JsValue) -> bool; /// Performs a dynamic check to see whether the `JsValue` provided /// is a value of this type. /// /// Unlike `instanceof`, this can be specialised to use a custom check by /// adding a `#[wasm_bindgen(is_type_of = callback)]` attribute to the /// type import declaration. /// /// Other than that, this is intended to be an internal implementation /// detail of `has_type` and you likely won't need to call this. fn is_type_of(val: &JsValue) -> bool { Self::instanceof(val) } /// Performs a zero-cost unchecked conversion from a `JsValue` into an /// instance of `Self` /// /// This is intended to be an internal implementation detail, you likely /// won't need to call this. fn unchecked_from_js(val: JsValue) -> Self; /// Performs a zero-cost unchecked conversion from a `&JsValue` into an /// instance of `&Self`. /// /// Note the safety of this method, which basically means that `Self` must /// be a newtype wrapper around `JsValue`. /// /// This is intended to be an internal implementation detail, you likely /// won't need to call this. fn unchecked_from_js_ref(val: &JsValue) -> &Self; } /// Trait implemented for wrappers around `JsValue`s generated by `#[wasm_bindgen]`. #[doc(hidden)] pub trait JsObject: JsCast + WasmDescribe {} wasm-bindgen-0.2.99/src/closure.rs000064400000000000000000000776421046102023000151310ustar 00000000000000//! Support for long-lived closures in `wasm-bindgen` //! //! This module defines the `Closure` type which is used to pass "owned //! closures" from Rust to JS. Some more details can be found on the `Closure` //! type itself. #![allow(clippy::fn_to_numeric_cast)] use alloc::boxed::Box; use alloc::string::String; use core::fmt; use core::mem::{self, ManuallyDrop}; use crate::convert::*; use crate::describe::*; use crate::throw_str; use crate::JsValue; use crate::UnwrapThrowExt; /// A handle to both a closure in Rust as well as JS closure which will invoke /// the Rust closure. /// /// A `Closure` is the primary way that a `'static` lifetime closure is /// transferred from Rust to JS. `Closure` currently requires that the closures /// it's created with have the `'static` lifetime in Rust for soundness reasons. /// /// This type is a "handle" in the sense that whenever it is dropped it will /// invalidate the JS closure that it refers to. Any usage of the closure in JS /// after the `Closure` has been dropped will raise an exception. It's then up /// to you to arrange for `Closure` to be properly deallocate at an appropriate /// location in your program. /// /// The type parameter on `Closure` is the type of closure that this represents. /// Currently this can only be the `Fn` and `FnMut` traits with up to 7 /// arguments (and an optional return value). /// /// # Examples /// /// Here are a number of examples of using `Closure`. /// /// ## Using the `setInterval` API /// /// Sample usage of `Closure` to invoke the `setInterval` API. /// /// ```rust,no_run /// use wasm_bindgen::prelude::*; /// /// #[wasm_bindgen] /// extern "C" { /// fn setInterval(closure: &Closure, time: u32) -> i32; /// fn clearInterval(id: i32); /// /// #[wasm_bindgen(js_namespace = console)] /// fn log(s: &str); /// } /// /// #[wasm_bindgen] /// pub struct IntervalHandle { /// interval_id: i32, /// _closure: Closure, /// } /// /// impl Drop for IntervalHandle { /// fn drop(&mut self) { /// clearInterval(self.interval_id); /// } /// } /// /// #[wasm_bindgen] /// pub fn run() -> IntervalHandle { /// // First up we use `Closure::new` to wrap up a Rust closure and create /// // a JS closure. /// let cb = Closure::new(|| { /// log("interval elapsed!"); /// }); /// /// // Next we pass this via reference to the `setInterval` function, and /// // `setInterval` gets a handle to the corresponding JS closure. /// let interval_id = setInterval(&cb, 1_000); /// /// // If we were to drop `cb` here it would cause an exception to be raised /// // whenever the interval elapses. Instead we *return* our handle back to JS /// // so JS can decide when to cancel the interval and deallocate the closure. /// IntervalHandle { /// interval_id, /// _closure: cb, /// } /// } /// ``` /// /// ## Casting a `Closure` to a `js_sys::Function` /// /// This is the same `setInterval` example as above, except it is using /// `web_sys` (which uses `js_sys::Function` for callbacks) instead of manually /// writing bindings to `setInterval` and other Web APIs. /// /// ```rust,ignore /// use wasm_bindgen::JsCast; /// /// #[wasm_bindgen] /// pub struct IntervalHandle { /// interval_id: i32, /// _closure: Closure, /// } /// /// impl Drop for IntervalHandle { /// fn drop(&mut self) { /// let window = web_sys::window().unwrap(); /// window.clear_interval_with_handle(self.interval_id); /// } /// } /// /// #[wasm_bindgen] /// pub fn run() -> Result { /// let cb = Closure::new(|| { /// web_sys::console::log_1(&"interval elapsed!".into()); /// }); /// /// let window = web_sys::window().unwrap(); /// let interval_id = window.set_interval_with_callback_and_timeout_and_arguments_0( /// // Note this method call, which uses `as_ref()` to get a `JsValue` /// // from our `Closure` which is then converted to a `&Function` /// // using the `JsCast::unchecked_ref` function. /// cb.as_ref().unchecked_ref(), /// 1_000, /// )?; /// /// // Same as above. /// Ok(IntervalHandle { /// interval_id, /// _closure: cb, /// }) /// } /// ``` /// /// ## Using `FnOnce` and `Closure::once` with `requestAnimationFrame` /// /// Because `requestAnimationFrame` only calls its callback once, we can use /// `FnOnce` and `Closure::once` with it. /// /// ```rust,no_run /// use wasm_bindgen::prelude::*; /// /// #[wasm_bindgen] /// extern "C" { /// fn requestAnimationFrame(closure: &Closure) -> u32; /// fn cancelAnimationFrame(id: u32); /// /// #[wasm_bindgen(js_namespace = console)] /// fn log(s: &str); /// } /// /// #[wasm_bindgen] /// pub struct AnimationFrameHandle { /// animation_id: u32, /// _closure: Closure, /// } /// /// impl Drop for AnimationFrameHandle { /// fn drop(&mut self) { /// cancelAnimationFrame(self.animation_id); /// } /// } /// /// // A type that will log a message when it is dropped. /// struct LogOnDrop(&'static str); /// impl Drop for LogOnDrop { /// fn drop(&mut self) { /// log(self.0); /// } /// } /// /// #[wasm_bindgen] /// pub fn run() -> AnimationFrameHandle { /// // We are using `Closure::once` which takes a `FnOnce`, so the function /// // can drop and/or move things that it closes over. /// let fired = LogOnDrop("animation frame fired or canceled"); /// let cb = Closure::once(move || drop(fired)); /// /// // Schedule the animation frame! /// let animation_id = requestAnimationFrame(&cb); /// /// // Again, return a handle to JS, so that the closure is not dropped /// // immediately and JS can decide whether to cancel the animation frame. /// AnimationFrameHandle { /// animation_id, /// _closure: cb, /// } /// } /// ``` /// /// ## Converting `FnOnce`s directly into JavaScript Functions with `Closure::once_into_js` /// /// If we don't want to allow a `FnOnce` to be eagerly dropped (maybe because we /// just want it to drop after it is called and don't care about cancellation) /// then we can use the `Closure::once_into_js` function. /// /// This is the same `requestAnimationFrame` example as above, but without /// supporting early cancellation. /// /// ``` /// use wasm_bindgen::prelude::*; /// /// #[wasm_bindgen] /// extern "C" { /// // We modify the binding to take an untyped `JsValue` since that is what /// // is returned by `Closure::once_into_js`. /// // /// // If we were using the `web_sys` binding for `requestAnimationFrame`, /// // then the call sites would cast the `JsValue` into a `&js_sys::Function` /// // using `f.unchecked_ref::()`. See the `web_sys` /// // example above for details. /// fn requestAnimationFrame(callback: JsValue); /// /// #[wasm_bindgen(js_namespace = console)] /// fn log(s: &str); /// } /// /// // A type that will log a message when it is dropped. /// struct LogOnDrop(&'static str); /// impl Drop for LogOnDrop { /// fn drop(&mut self) { /// log(self.0); /// } /// } /// /// #[wasm_bindgen] /// pub fn run() { /// // We are using `Closure::once_into_js` which takes a `FnOnce` and /// // converts it into a JavaScript function, which is returned as a /// // `JsValue`. /// let fired = LogOnDrop("animation frame fired"); /// let cb = Closure::once_into_js(move || drop(fired)); /// /// // Schedule the animation frame! /// requestAnimationFrame(cb); /// /// // No need to worry about whether or not we drop a `Closure` /// // here or return some sort of handle to JS! /// } /// ``` pub struct Closure { js: ManuallyDrop, data: ManuallyDrop>, } union FatPtr { ptr: *mut T, fields: (usize, usize), } impl Closure where T: ?Sized + WasmClosure, { /// Creates a new instance of `Closure` from the provided Rust function. /// /// Note that the closure provided here, `F`, has a few requirements /// associated with it: /// /// * It must implement `Fn` or `FnMut` (for `FnOnce` functions see /// `Closure::once` and `Closure::once_into_js`). /// /// * It must be `'static`, aka no stack references (use the `move` /// keyword). /// /// * It can have at most 7 arguments. /// /// * Its arguments and return values are all types that can be shared with /// JS (i.e. have `#[wasm_bindgen]` annotations or are simple numbers, /// etc.) pub fn new(t: F) -> Closure where F: IntoWasmClosure + 'static, { Closure::wrap(Box::new(t).unsize()) } /// A more direct version of `Closure::new` which creates a `Closure` from /// a `Box`/`Box`, which is how it's kept internally. pub fn wrap(mut data: Box) -> Closure { assert_eq!(mem::size_of::<*const T>(), mem::size_of::>()); let (a, b) = unsafe { FatPtr { ptr: &mut *data as *mut T, } .fields }; // Here we need to create a `JsValue` with the data and `T::invoke()` // function pointer. To do that we... take a few unconventional turns. // In essence what happens here is this: // // 1. First up, below we call a function, `breaks_if_inlined`. This // function, as the name implies, does not work if it's inlined. // More on that in a moment. // 2. This function internally calls a special import recognized by the // `wasm-bindgen` CLI tool, `__wbindgen_describe_closure`. This // imported symbol is similar to `__wbindgen_describe` in that it's // not intended to show up in the final binary but it's an // intermediate state for a `wasm-bindgen` binary. // 3. The `__wbindgen_describe_closure` import is namely passed a // descriptor function, monomorphized for each invocation. // // Most of this doesn't actually make sense to happen at runtime! The // real magic happens when `wasm-bindgen` comes along and updates our // generated code. When `wasm-bindgen` runs it performs a few tasks: // // * First, it finds all functions that call // `__wbindgen_describe_closure`. These are all `breaks_if_inlined` // defined below as the symbol isn't called anywhere else. // * Next, `wasm-bindgen` executes the `breaks_if_inlined` // monomorphized functions, passing it dummy arguments. This will // execute the function just enough to invoke the special import, // namely telling us about the function pointer that is the describe // shim. // * This knowledge is then used to actually find the descriptor in the // function table which is then executed to figure out the signature // of the closure. // * Finally, and probably most heinously, the call to // `breaks_if_inlined` is rewritten to call an otherwise globally // imported function. This globally imported function will generate // the `JsValue` for this closure specialized for the signature in // question. // // Later on `wasm-gc` will clean up all the dead code and ensure that // we don't actually call `__wbindgen_describe_closure` at runtime. This // means we will end up not actually calling `breaks_if_inlined` in the // final binary, all calls to that function should be pruned. // // See crates/cli-support/src/js/closures.rs for a more information // about what's going on here. #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] extern "C" fn describe() { inform(CLOSURE); T::describe() } #[inline(never)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe fn breaks_if_inlined(a: usize, b: usize) -> u32 { super::__wbindgen_describe_closure(a as u32, b as u32, describe:: as usize as u32) } let idx = unsafe { breaks_if_inlined::(a, b) }; Closure { js: ManuallyDrop::new(JsValue::_new(idx)), data: ManuallyDrop::new(data), } } /// Release memory management of this closure from Rust to the JS GC. /// /// When a `Closure` is dropped it will release the Rust memory and /// invalidate the associated JS closure, but this isn't always desired. /// Some callbacks are alive for the entire duration of the program or for a /// lifetime dynamically managed by the JS GC. This function can be used /// to drop this `Closure` while keeping the associated JS function still /// valid. /// /// If the platform supports weak references, the Rust memory will be /// reclaimed when the JS closure is GC'd. If weak references is not /// supported, this can be dangerous if this function is called many times /// in an application because the memory leak will overwhelm the page /// quickly and crash the wasm. pub fn into_js_value(self) -> JsValue { let idx = self.js.idx; mem::forget(self); JsValue::_new(idx) } /// Same as `into_js_value`, but doesn't return a value. pub fn forget(self) { drop(self.into_js_value()); } } // NB: we use a specific `T` for this `Closure` impl block to avoid every // call site having to provide an explicit, turbo-fished type like // `Closure::::once(...)`. impl Closure { /// Create a `Closure` from a function that can only be called once. /// /// Since we have no way of enforcing that JS cannot attempt to call this /// `FnOne(A...) -> R` more than once, this produces a `Closure R>` that will dynamically throw a JavaScript error if called more /// than once. /// /// # Example /// /// ```rust,no_run /// use wasm_bindgen::prelude::*; /// /// // Create an non-`Copy`, owned `String`. /// let mut s = String::from("Hello"); /// /// // Close over `s`. Since `f` returns `s`, it is `FnOnce` and can only be /// // called once. If it was called a second time, it wouldn't have any `s` /// // to work with anymore! /// let f = move || { /// s += ", World!"; /// s /// }; /// /// // Create a `Closure` from `f`. Note that the `Closure`'s type parameter /// // is `FnMut`, even though `f` is `FnOnce`. /// let closure: Closure String> = Closure::once(f); /// ``` pub fn once(fn_once: F) -> Closure where F: 'static + WasmClosureFnOnce, { Closure::wrap(fn_once.into_fn_mut()) } /// Convert a `FnOnce(A...) -> R` into a JavaScript `Function` object. /// /// If the JavaScript function is invoked more than once, it will throw an /// exception. /// /// Unlike `Closure::once`, this does *not* return a `Closure` that can be /// dropped before the function is invoked to deallocate the closure. The /// only way the `FnOnce` is deallocated is by calling the JavaScript /// function. If the JavaScript function is never called then the `FnOnce` /// and everything it closes over will leak. /// /// ```rust,ignore /// use wasm_bindgen::{prelude::*, JsCast}; /// /// let f = Closure::once_into_js(move || { /// // ... /// }); /// /// assert!(f.is_instance_of::()); /// ``` pub fn once_into_js(fn_once: F) -> JsValue where F: 'static + WasmClosureFnOnce, { fn_once.into_js_function() } } /// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that /// will throw if ever called more than once. #[doc(hidden)] pub trait WasmClosureFnOnce: 'static { type FnMut: ?Sized + 'static + WasmClosure; fn into_fn_mut(self) -> Box; fn into_js_function(self) -> JsValue; } impl AsRef for Closure { fn as_ref(&self) -> &JsValue { &self.js } } impl WasmDescribe for Closure where T: WasmClosure + ?Sized, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(EXTERNREF); } } // `Closure` can only be passed by reference to imports. impl IntoWasmAbi for &Closure where T: WasmClosure + ?Sized, { type Abi = u32; fn into_abi(self) -> u32 { (&*self.js).into_abi() } } impl OptionIntoWasmAbi for &Closure where T: WasmClosure + ?Sized, { fn none() -> Self::Abi { 0 } } fn _check() { fn _assert() {} _assert::<&Closure>(); _assert::<&Closure>(); _assert::<&Closure String>>(); _assert::<&Closure>(); _assert::<&Closure>(); _assert::<&Closure String>>(); } impl fmt::Debug for Closure where T: ?Sized, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Closure {{ ... }}") } } impl Drop for Closure where T: ?Sized, { fn drop(&mut self) { unsafe { // this will implicitly drop our strong reference in addition to // invalidating all future invocations of the closure if super::__wbindgen_cb_drop(self.js.idx) != 0 { ManuallyDrop::drop(&mut self.data); } } } } /// An internal trait for the `Closure` type. /// /// This trait is not stable and it's not recommended to use this in bounds or /// implement yourself. #[doc(hidden)] pub unsafe trait WasmClosure { fn describe(); } /// An internal trait for the `Closure` type. /// /// This trait is not stable and it's not recommended to use this in bounds or /// implement yourself. #[doc(hidden)] pub trait IntoWasmClosure { fn unsize(self: Box) -> Box; } // The memory safety here in these implementations below is a bit tricky. We // want to be able to drop the `Closure` object from within the invocation of a // `Closure` for cases like promises. That means that while it's running we // might drop the `Closure`, but that shouldn't invalidate the environment yet. // // Instead what we do is to wrap closures in `Rc` variables. The main `Closure` // has a strong reference count which keeps the trait object alive. Each // invocation of a closure then *also* clones this and gets a new reference // count. When the closure returns it will release the reference count. // // This means that if the main `Closure` is dropped while it's being invoked // then destruction is deferred until execution returns. Otherwise it'll // deallocate data immediately. macro_rules! doit { ($( ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($( unsafe impl<$($var,)* R> WasmClosure for dyn Fn($($var),*) -> R + 'static where $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, $( $arg1: <$var::Abi as WasmAbi>::Prim1, $arg2: <$var::Abi as WasmAbi>::Prim2, $arg3: <$var::Abi as WasmAbi>::Prim3, $arg4: <$var::Abi as WasmAbi>::Prim4, )* ) -> WasmRet { if a == 0 { throw_str("closure invoked after being dropped"); } // Make sure all stack variables are converted before we // convert `ret` as it may throw (for `Result`, for // example) let ret = { let f: *const dyn Fn($($var),*) -> R = FatPtr { fields: (a, b) }.ptr; $( let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4)); )* (*f)($($var),*) }; ret.return_abi().into() } inform(invoke::<$($var,)* R> as usize as u32); unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, ) { // This can be called by the JS glue in erroneous situations // such as when the closure has already been destroyed. If // that's the case let's not make things worse by // segfaulting and/or asserting, so just ignore null // pointers. if a == 0 { return; } drop(Box::from_raw(FatPtr:: R> { fields: (a, b) }.ptr)); } inform(destroy::<$($var,)* R> as usize as u32); <&Self>::describe(); } } unsafe impl<$($var,)* R> WasmClosure for dyn FnMut($($var),*) -> R + 'static where $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, $( $arg1: <$var::Abi as WasmAbi>::Prim1, $arg2: <$var::Abi as WasmAbi>::Prim2, $arg3: <$var::Abi as WasmAbi>::Prim3, $arg4: <$var::Abi as WasmAbi>::Prim4, )* ) -> WasmRet { if a == 0 { throw_str("closure invoked recursively or after being dropped"); } // Make sure all stack variables are converted before we // convert `ret` as it may throw (for `Result`, for // example) let ret = { let f: *const dyn FnMut($($var),*) -> R = FatPtr { fields: (a, b) }.ptr; let f = f as *mut dyn FnMut($($var),*) -> R; $( let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4)); )* (*f)($($var),*) }; ret.return_abi().into() } inform(invoke::<$($var,)* R> as usize as u32); unsafe extern fn destroy<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, ) { // See `Fn()` above for why we simply return if a == 0 { return; } drop(Box::from_raw(FatPtr:: R> { fields: (a, b) }.ptr)); } inform(destroy::<$($var,)* R> as usize as u32); <&mut Self>::describe(); } } #[allow(non_snake_case, unused_parens)] impl WasmClosureFnOnce<($($var),*), R> for T where T: 'static + FnOnce($($var),*) -> R, $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static { type FnMut = dyn FnMut($($var),*) -> R; fn into_fn_mut(self) -> Box { let mut me = Some(self); Box::new(move |$($var),*| { let me = me.take().expect_throw("FnOnce called more than once"); me($($var),*) }) } fn into_js_function(self) -> JsValue { use alloc::rc::Rc; use crate::__rt::WasmRefCell; let mut me = Some(self); let rc1 = Rc::new(WasmRefCell::new(None)); let rc2 = rc1.clone(); let closure = Closure::wrap(Box::new(move |$($var),*| { // Invoke ourself and get the result. let me = me.take().expect_throw("FnOnce called more than once"); let result = me($($var),*); // And then drop the `Rc` holding this function's `Closure` // alive. debug_assert_eq!(Rc::strong_count(&rc2), 1); let option_closure = rc2.borrow_mut().take(); debug_assert!(option_closure.is_some()); drop(option_closure); result }) as Box R>); let js_val = closure.as_ref().clone(); *rc1.borrow_mut() = Some(closure); debug_assert_eq!(Rc::strong_count(&rc1), 2); drop(rc1); js_val } } impl IntoWasmClosure R> for T where T: 'static + FnMut($($var),*) -> R, $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static, { fn unsize(self: Box) -> Box R> { self } } impl IntoWasmClosure R> for T where T: 'static + Fn($($var),*) -> R, $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static, { fn unsize(self: Box) -> Box R> { self } } )*) } doit! { () (A a1 a2 a3 a4) (A a1 a2 a3 a4 B b1 b2 b3 b4) (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4) (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4) (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4) (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4) (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4) (A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4 H h1 h2 h3 h4) } // Copy the above impls down here for where there's only one argument and it's a // reference. We could add more impls for more kinds of references, but it // becomes a combinatorial explosion quickly. Let's see how far we can get with // just this one! Maybe someone else can figure out voodoo so we don't have to // duplicate. unsafe impl WasmClosure for dyn Fn(&A) -> R where A: RefFromWasmAbi, R: ReturnWasmAbi + 'static, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke( a: usize, b: usize, arg1: ::Prim1, arg2: ::Prim2, arg3: ::Prim3, arg4: ::Prim4, ) -> WasmRet { if a == 0 { throw_str("closure invoked after being dropped"); } // Make sure all stack variables are converted before we // convert `ret` as it may throw (for `Result`, for // example) let ret = { let f: *const dyn Fn(&A) -> R = FatPtr { fields: (a, b) }.ptr; let arg = ::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4)); (*f)(&*arg) }; ret.return_abi().into() } inform(invoke:: as usize as u32); #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn destroy(a: usize, b: usize) { // See `Fn()` above for why we simply return if a == 0 { return; } drop(Box::from_raw( FatPtr:: R> { fields: (a, b) }.ptr, )); } inform(destroy:: as usize as u32); <&Self>::describe(); } } unsafe impl WasmClosure for dyn FnMut(&A) -> R where A: RefFromWasmAbi, R: ReturnWasmAbi + 'static, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke( a: usize, b: usize, arg1: ::Prim1, arg2: ::Prim2, arg3: ::Prim3, arg4: ::Prim4, ) -> WasmRet { if a == 0 { throw_str("closure invoked recursively or after being dropped"); } // Make sure all stack variables are converted before we // convert `ret` as it may throw (for `Result`, for // example) let ret = { let f: *const dyn FnMut(&A) -> R = FatPtr { fields: (a, b) }.ptr; let f = f as *mut dyn FnMut(&A) -> R; let arg = ::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4)); (*f)(&*arg) }; ret.return_abi().into() } inform(invoke:: as usize as u32); #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn destroy(a: usize, b: usize) { // See `Fn()` above for why we simply return if a == 0 { return; } drop(Box::from_raw( FatPtr:: R> { fields: (a, b) }.ptr, )); } inform(destroy:: as usize as u32); <&mut Self>::describe(); } } #[allow(non_snake_case)] impl WasmClosureFnOnce<(&A,), R> for T where T: 'static + FnOnce(&A) -> R, A: RefFromWasmAbi + 'static, R: ReturnWasmAbi + 'static, { type FnMut = dyn FnMut(&A) -> R; fn into_fn_mut(self) -> Box { let mut me = Some(self); Box::new(move |arg| { let me = me.take().expect_throw("FnOnce called more than once"); me(arg) }) } fn into_js_function(self) -> JsValue { use crate::__rt::WasmRefCell; use alloc::rc::Rc; let mut me = Some(self); let rc1 = Rc::new(WasmRefCell::new(None)); let rc2 = rc1.clone(); let closure = Closure::wrap(Box::new(move |arg: &A| { // Invoke ourself and get the result. let me = me.take().expect_throw("FnOnce called more than once"); let result = me(arg); // And then drop the `Rc` holding this function's `Closure` // alive. debug_assert_eq!(Rc::strong_count(&rc2), 1); let option_closure = rc2.borrow_mut().take(); debug_assert!(option_closure.is_some()); drop(option_closure); result }) as Box R>); let js_val = closure.as_ref().clone(); *rc1.borrow_mut() = Some(closure); debug_assert_eq!(Rc::strong_count(&rc1), 2); drop(rc1); js_val } } wasm-bindgen-0.2.99/src/convert/closures.rs000064400000000000000000000204771046102023000167660ustar 00000000000000#![allow(clippy::fn_to_numeric_cast)] use core::mem; use crate::convert::slices::WasmSlice; use crate::convert::RefFromWasmAbi; use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet}; use crate::describe::{inform, WasmDescribe, FUNCTION}; use crate::throw_str; macro_rules! stack_closures { ($( ($cnt:tt $invoke:ident $invoke_mut:ident $($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($( impl<'a, 'b, $($var,)* R> IntoWasmAbi for &'a (dyn Fn($($var),*) -> R + 'b) where $($var: FromWasmAbi,)* R: ReturnWasmAbi { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32 } } } } #[allow(non_snake_case)] unsafe extern "C" fn $invoke<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, $( $arg1: <$var::Abi as WasmAbi>::Prim1, $arg2: <$var::Abi as WasmAbi>::Prim2, $arg3: <$var::Abi as WasmAbi>::Prim3, $arg4: <$var::Abi as WasmAbi>::Prim4, )* ) -> WasmRet { if a == 0 { throw_str("closure invoked after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &dyn Fn($($var),*) -> R = mem::transmute((a, b)); $( let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4)); )* f($($var),*) }; ret.return_abi().into() } impl<'a, $($var,)* R> WasmDescribe for dyn Fn($($var),*) -> R + 'a where $($var: FromWasmAbi,)* R: ReturnWasmAbi { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform($invoke::<$($var,)* R> as usize as u32); inform($cnt); $(<$var as WasmDescribe>::describe();)* ::describe(); ::describe(); } } impl<'a, 'b, $($var,)* R> IntoWasmAbi for &'a mut (dyn FnMut($($var),*) -> R + 'b) where $($var: FromWasmAbi,)* R: ReturnWasmAbi { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32 } } } } #[allow(non_snake_case)] unsafe extern "C" fn $invoke_mut<$($var: FromWasmAbi,)* R: ReturnWasmAbi>( a: usize, b: usize, $( $arg1: <$var::Abi as WasmAbi>::Prim1, $arg2: <$var::Abi as WasmAbi>::Prim2, $arg3: <$var::Abi as WasmAbi>::Prim3, $arg4: <$var::Abi as WasmAbi>::Prim4, )* ) -> WasmRet { if a == 0 { throw_str("closure invoked recursively or after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &mut dyn FnMut($($var),*) -> R = mem::transmute((a, b)); $( let $var = <$var as FromWasmAbi>::from_abi($var::Abi::join($arg1, $arg2, $arg3, $arg4)); )* f($($var),*) }; ret.return_abi().into() } impl<'a, $($var,)* R> WasmDescribe for dyn FnMut($($var),*) -> R + 'a where $($var: FromWasmAbi,)* R: ReturnWasmAbi { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform($invoke_mut::<$($var,)* R> as usize as u32); inform($cnt); $(<$var as WasmDescribe>::describe();)* ::describe(); ::describe(); } } )*) } stack_closures! { (0 invoke0 invoke0_mut) (1 invoke1 invoke1_mut A a1 a2 a3 a4) (2 invoke2 invoke2_mut A a1 a2 a3 a4 B b1 b2 b3 b4) (3 invoke3 invoke3_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4) (4 invoke4 invoke4_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4) (5 invoke5 invoke5_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4) (6 invoke6 invoke6_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4) (7 invoke7 invoke7_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4) (8 invoke8 invoke8_mut A a1 a2 a3 a4 B b1 b2 b3 b4 C c1 c2 c3 c4 D d1 d2 d3 d4 E e1 e2 e3 e4 F f1 f2 f3 f4 G g1 g2 g3 g4 H h1 h2 h3 h4) } impl IntoWasmAbi for &(dyn Fn(&A) -> R + '_) where A: RefFromWasmAbi, R: ReturnWasmAbi, { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32, } } } } #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke1_ref( a: usize, b: usize, arg1: ::Prim1, arg2: ::Prim2, arg3: ::Prim3, arg4: ::Prim4, ) -> WasmRet { if a == 0 { throw_str("closure invoked after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &dyn Fn(&A) -> R = mem::transmute((a, b)); let arg = ::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4)); f(&*arg) }; ret.return_abi().into() } impl WasmDescribe for dyn Fn(&A) -> R + '_ where A: RefFromWasmAbi, R: ReturnWasmAbi, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform(invoke1_ref:: as usize as u32); inform(1); <&A as WasmDescribe>::describe(); ::describe(); ::describe(); } } impl IntoWasmAbi for &mut (dyn FnMut(&A) -> R + '_) where A: RefFromWasmAbi, R: ReturnWasmAbi, { type Abi = WasmSlice; fn into_abi(self) -> WasmSlice { unsafe { let (a, b): (usize, usize) = mem::transmute(self); WasmSlice { ptr: a as u32, len: b as u32, } } } } #[allow(non_snake_case)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] unsafe extern "C" fn invoke1_mut_ref( a: usize, b: usize, arg1: ::Prim1, arg2: ::Prim2, arg3: ::Prim3, arg4: ::Prim4, ) -> WasmRet { if a == 0 { throw_str("closure invoked recursively or after being dropped"); } // Scope all local variables before we call `return_abi` to // ensure they're all destroyed as `return_abi` may throw let ret = { let f: &mut dyn FnMut(&A) -> R = mem::transmute((a, b)); let arg = ::ref_from_abi(A::Abi::join(arg1, arg2, arg3, arg4)); f(&*arg) }; ret.return_abi().into() } impl WasmDescribe for dyn FnMut(&A) -> R + '_ where A: RefFromWasmAbi, R: ReturnWasmAbi, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(FUNCTION); inform(invoke1_mut_ref:: as usize as u32); inform(1); <&A as WasmDescribe>::describe(); ::describe(); ::describe(); } } wasm-bindgen-0.2.99/src/convert/impls.rs000064400000000000000000000340371046102023000162500ustar 00000000000000use alloc::boxed::Box; use alloc::vec::Vec; use core::char; use core::fmt::Debug; use core::mem::{self, ManuallyDrop}; use core::ptr::NonNull; use crate::convert::traits::{WasmAbi, WasmPrimitive}; use crate::convert::TryFromJsValue; use crate::convert::{FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, RefFromWasmAbi}; use crate::convert::{OptionFromWasmAbi, OptionIntoWasmAbi, ReturnWasmAbi}; use crate::{Clamped, JsError, JsValue, UnwrapThrowExt}; // Primitive types can always be passed over the ABI. impl WasmAbi for T { type Prim1 = Self; type Prim2 = (); type Prim3 = (); type Prim4 = (); #[inline] fn split(self) -> (Self, (), (), ()) { (self, (), (), ()) } #[inline] fn join(prim: Self, _: (), _: (), _: ()) -> Self { prim } } impl WasmAbi for i128 { type Prim1 = u64; type Prim2 = u64; type Prim3 = (); type Prim4 = (); #[inline] fn split(self) -> (u64, u64, (), ()) { let low = self as u64; let high = (self >> 64) as u64; (low, high, (), ()) } #[inline] fn join(low: u64, high: u64, _: (), _: ()) -> Self { ((high as u128) << 64 | low as u128) as i128 } } impl WasmAbi for u128 { type Prim1 = u64; type Prim2 = u64; type Prim3 = (); type Prim4 = (); #[inline] fn split(self) -> (u64, u64, (), ()) { let low = self as u64; let high = (self >> 64) as u64; (low, high, (), ()) } #[inline] fn join(low: u64, high: u64, _: (), _: ()) -> Self { (high as u128) << 64 | low as u128 } } impl> WasmAbi for Option { /// Whether this `Option` is a `Some` value. type Prim1 = u32; type Prim2 = T::Prim1; type Prim3 = T::Prim2; type Prim4 = T::Prim3; #[inline] fn split(self) -> (u32, T::Prim1, T::Prim2, T::Prim3) { match self { None => ( 0, Default::default(), Default::default(), Default::default(), ), Some(value) => { let (prim1, prim2, prim3, ()) = value.split(); (1, prim1, prim2, prim3) } } } #[inline] fn join(is_some: u32, prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3) -> Self { if is_some == 0 { None } else { Some(T::join(prim1, prim2, prim3, ())) } } } macro_rules! type_wasm_native { ($($t:tt as $c:tt)*) => ($( impl IntoWasmAbi for $t { type Abi = $c; #[inline] fn into_abi(self) -> $c { self as $c } } impl FromWasmAbi for $t { type Abi = $c; #[inline] unsafe fn from_abi(js: $c) -> Self { js as $t } } impl IntoWasmAbi for Option<$t> { type Abi = Option<$c>; #[inline] fn into_abi(self) -> Self::Abi { self.map(|v| v as $c) } } impl FromWasmAbi for Option<$t> { type Abi = Option<$c>; #[inline] unsafe fn from_abi(js: Self::Abi) -> Self { js.map(|v: $c| v as $t) } } )*) } type_wasm_native!( i64 as i64 u64 as u64 i128 as i128 u128 as u128 f64 as f64 ); /// The sentinel value is 2^32 + 1 for 32-bit primitive types. /// /// 2^32 + 1 is used, because it's the smallest positive integer that cannot be /// represented by any 32-bit primitive. While any value >= 2^32 works as a /// sentinel value for 32-bit integers, it's a bit more tricky for `f32`. `f32` /// can represent all powers of 2 up to 2^127 exactly. And between 2^32 and 2^33, /// `f32` can represent all integers 2^32+512*k exactly. const F64_ABI_OPTION_SENTINEL: f64 = 4294967297_f64; macro_rules! type_wasm_native_f64_option { ($($t:tt as $c:tt)*) => ($( impl IntoWasmAbi for $t { type Abi = $c; #[inline] fn into_abi(self) -> $c { self as $c } } impl FromWasmAbi for $t { type Abi = $c; #[inline] unsafe fn from_abi(js: $c) -> Self { js as $t } } impl IntoWasmAbi for Option<$t> { type Abi = f64; #[inline] fn into_abi(self) -> Self::Abi { self.map(|v| v as $c as f64).unwrap_or(F64_ABI_OPTION_SENTINEL) } } impl FromWasmAbi for Option<$t> { type Abi = f64; #[inline] unsafe fn from_abi(js: Self::Abi) -> Self { if js == F64_ABI_OPTION_SENTINEL { None } else { Some(js as $c as $t) } } } )*) } type_wasm_native_f64_option!( i32 as i32 isize as i32 u32 as u32 usize as u32 f32 as f32 ); /// The sentinel value is 0xFF_FFFF for primitives with less than 32 bits. /// /// This value is used, so all small primitive types (`bool`, `i8`, `u8`, /// `i16`, `u16`, `char`) can use the same JS glue code. `char::MAX` is /// 0x10_FFFF btw. const U32_ABI_OPTION_SENTINEL: u32 = 0x00FF_FFFFu32; macro_rules! type_abi_as_u32 { ($($t:tt)*) => ($( impl IntoWasmAbi for $t { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self as u32 } } impl FromWasmAbi for $t { type Abi = u32; #[inline] unsafe fn from_abi(js: u32) -> Self { js as $t } } impl OptionIntoWasmAbi for $t { #[inline] fn none() -> u32 { U32_ABI_OPTION_SENTINEL } } impl OptionFromWasmAbi for $t { #[inline] fn is_none(js: &u32) -> bool { *js == U32_ABI_OPTION_SENTINEL } } )*) } type_abi_as_u32!(i8 u8 i16 u16); impl IntoWasmAbi for bool { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self as u32 } } impl FromWasmAbi for bool { type Abi = u32; #[inline] unsafe fn from_abi(js: u32) -> bool { js != 0 } } impl OptionIntoWasmAbi for bool { #[inline] fn none() -> u32 { U32_ABI_OPTION_SENTINEL } } impl OptionFromWasmAbi for bool { #[inline] fn is_none(js: &u32) -> bool { *js == U32_ABI_OPTION_SENTINEL } } impl IntoWasmAbi for char { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self as u32 } } impl FromWasmAbi for char { type Abi = u32; #[inline] unsafe fn from_abi(js: u32) -> char { // SAFETY: Checked in bindings. char::from_u32_unchecked(js) } } impl OptionIntoWasmAbi for char { #[inline] fn none() -> u32 { U32_ABI_OPTION_SENTINEL } } impl OptionFromWasmAbi for char { #[inline] fn is_none(js: &u32) -> bool { *js == U32_ABI_OPTION_SENTINEL } } impl IntoWasmAbi for *const T { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self as u32 } } impl FromWasmAbi for *const T { type Abi = u32; #[inline] unsafe fn from_abi(js: u32) -> *const T { js as *const T } } impl IntoWasmAbi for Option<*const T> { type Abi = f64; #[inline] fn into_abi(self) -> f64 { self.map(|ptr| ptr as u32 as f64) .unwrap_or(F64_ABI_OPTION_SENTINEL) } } impl FromWasmAbi for Option<*const T> { type Abi = f64; #[inline] unsafe fn from_abi(js: f64) -> Option<*const T> { if js == F64_ABI_OPTION_SENTINEL { None } else { Some(js as u32 as *const T) } } } impl IntoWasmAbi for *mut T { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self as u32 } } impl FromWasmAbi for *mut T { type Abi = u32; #[inline] unsafe fn from_abi(js: u32) -> *mut T { js as *mut T } } impl IntoWasmAbi for Option<*mut T> { type Abi = f64; #[inline] fn into_abi(self) -> f64 { self.map(|ptr| ptr as u32 as f64) .unwrap_or(F64_ABI_OPTION_SENTINEL) } } impl FromWasmAbi for Option<*mut T> { type Abi = f64; #[inline] unsafe fn from_abi(js: f64) -> Option<*mut T> { if js == F64_ABI_OPTION_SENTINEL { None } else { Some(js as u32 as *mut T) } } } impl IntoWasmAbi for NonNull { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self.as_ptr() as u32 } } impl OptionIntoWasmAbi for NonNull { #[inline] fn none() -> u32 { 0 } } impl FromWasmAbi for NonNull { type Abi = u32; #[inline] unsafe fn from_abi(js: Self::Abi) -> Self { // SAFETY: Checked in bindings. NonNull::new_unchecked(js as *mut T) } } impl OptionFromWasmAbi for NonNull { #[inline] fn is_none(js: &u32) -> bool { *js == 0 } } impl IntoWasmAbi for JsValue { type Abi = u32; #[inline] fn into_abi(self) -> u32 { let ret = self.idx; mem::forget(self); ret } } impl FromWasmAbi for JsValue { type Abi = u32; #[inline] unsafe fn from_abi(js: u32) -> JsValue { JsValue::_new(js) } } impl IntoWasmAbi for &JsValue { type Abi = u32; #[inline] fn into_abi(self) -> u32 { self.idx } } impl RefFromWasmAbi for JsValue { type Abi = u32; type Anchor = ManuallyDrop; #[inline] unsafe fn ref_from_abi(js: u32) -> Self::Anchor { ManuallyDrop::new(JsValue::_new(js)) } } impl LongRefFromWasmAbi for JsValue { type Abi = u32; type Anchor = JsValue; #[inline] unsafe fn long_ref_from_abi(js: u32) -> Self::Anchor { Self::from_abi(js) } } impl IntoWasmAbi for Option { type Abi = T::Abi; #[inline] fn into_abi(self) -> T::Abi { match self { None => T::none(), Some(me) => me.into_abi(), } } } impl FromWasmAbi for Option { type Abi = T::Abi; #[inline] unsafe fn from_abi(js: T::Abi) -> Self { if T::is_none(&js) { None } else { Some(T::from_abi(js)) } } } impl IntoWasmAbi for Clamped { type Abi = T::Abi; #[inline] fn into_abi(self) -> Self::Abi { self.0.into_abi() } } impl FromWasmAbi for Clamped { type Abi = T::Abi; #[inline] unsafe fn from_abi(js: T::Abi) -> Self { Clamped(T::from_abi(js)) } } impl IntoWasmAbi for () { type Abi = (); #[inline] fn into_abi(self) { self } } impl> WasmAbi for Result { type Prim1 = T::Prim1; type Prim2 = T::Prim2; // The order of primitives here is such that we can pop() the possible error // first, deal with it and move on. Later primitives are popped off the // stack first. /// If this `Result` is an `Err`, the error value. type Prim3 = u32; /// Whether this `Result` is an `Err`. type Prim4 = u32; #[inline] fn split(self) -> (T::Prim1, T::Prim2, u32, u32) { match self { Ok(value) => { let (prim1, prim2, (), ()) = value.split(); (prim1, prim2, 0, 0) } Err(err) => (Default::default(), Default::default(), err, 1), } } #[inline] fn join(prim1: T::Prim1, prim2: T::Prim2, err: u32, is_err: u32) -> Self { if is_err == 0 { Ok(T::join(prim1, prim2, (), ())) } else { Err(err) } } } impl ReturnWasmAbi for Result where T: IntoWasmAbi, E: Into, T::Abi: WasmAbi, { type Abi = Result; #[inline] fn return_abi(self) -> Self::Abi { match self { Ok(v) => Ok(v.into_abi()), Err(e) => { let jsval = e.into(); Err(jsval.into_abi()) } } } } impl IntoWasmAbi for JsError { type Abi = ::Abi; fn into_abi(self) -> Self::Abi { self.value.into_abi() } } /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. // Note: this can't take `&[T]` because the `Into` impl needs // ownership of `T`. pub fn js_value_vector_into_abi>( vector: Box<[T]>, ) -> as IntoWasmAbi>::Abi { let js_vals: Box<[JsValue]> = vector.into_vec().into_iter().map(|x| x.into()).collect(); js_vals.into_abi() } /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub unsafe fn js_value_vector_from_abi( js: as FromWasmAbi>::Abi, ) -> Box<[T]> where T::Error: Debug, { let js_vals = as FromWasmAbi>::from_abi(js); let mut result = Vec::with_capacity(js_vals.len()); for value in js_vals { // We push elements one-by-one instead of using `collect` in order to improve // error messages. When using `collect`, this `expect_throw` is buried in a // giant chain of internal iterator functions, which results in the actual // function that takes this `Vec` falling off the end of the call stack. // So instead, make sure to call it directly within this function. // // This is only a problem in debug mode. Since this is the browser's error stack // we're talking about, it can only see functions that actually make it to the // final Wasm binary (i.e., not inlined functions). All of those internal // iterator functions get inlined in release mode, and so they don't show up. result.push( T::try_from_js_value(value).expect_throw("array contains a value of the wrong type"), ); } result.into_boxed_slice() } wasm-bindgen-0.2.99/src/convert/mod.rs000064400000000000000000000004461046102023000157000ustar 00000000000000//! # ⚠️ Unstable //! //! This is an internal module, no stability guarantees are provided. Use at //! your own risk. #![allow(clippy::missing_safety_doc)] mod closures; mod impls; mod slices; mod traits; pub use self::impls::*; pub use self::slices::WasmSlice; pub use self::traits::*; wasm-bindgen-0.2.99/src/convert/slices.rs000064400000000000000000000272101046102023000164010ustar 00000000000000use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use core::mem::{self, MaybeUninit}; use core::ops::{Deref, DerefMut}; use core::str; use crate::__wbindgen_copy_to_typed_array; use crate::cast::JsObject; use crate::convert::{js_value_vector_from_abi, js_value_vector_into_abi}; use crate::convert::{ FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi, VectorFromWasmAbi, VectorIntoWasmAbi, WasmAbi, }; use crate::describe::*; use crate::JsValue; use cfg_if::cfg_if; /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. // note: `WasmAbi` types do not need to be FFI-safe themselves, it's just more // convenient to directly write `WasmSlice` in some of the manually-written FFI // functions in `lib.rs` rather than `WasmRet`. #[repr(C)] pub struct WasmSlice { pub ptr: u32, pub len: u32, } impl WasmAbi for WasmSlice { /// `self.ptr` type Prim1 = u32; /// `self.len` type Prim2 = u32; type Prim3 = (); type Prim4 = (); #[inline] fn split(self) -> (u32, u32, (), ()) { (self.ptr, self.len, (), ()) } #[inline] fn join(ptr: u32, len: u32, _: (), _: ()) -> Self { Self { ptr, len } } } #[inline] fn null_slice() -> WasmSlice { WasmSlice { ptr: 0, len: 0 } } pub struct WasmMutSlice { pub slice: WasmSlice, pub idx: u32, } impl WasmAbi for WasmMutSlice { /// `self.slice.ptr` type Prim1 = u32; /// `self.slice.len` type Prim2 = u32; /// `self.idx` type Prim3 = u32; type Prim4 = (); #[inline] fn split(self) -> (u32, u32, u32, ()) { (self.slice.ptr, self.slice.len, self.idx, ()) } #[inline] fn join(ptr: u32, len: u32, idx: u32, _: ()) -> Self { Self { slice: WasmSlice { ptr, len }, idx, } } } /// The representation of a mutable slice passed from JS to Rust. pub struct MutSlice { /// A copy of the data in the JS typed array. contents: Box<[T]>, /// A reference to the original JS typed array. js: JsValue, } impl Drop for MutSlice { fn drop(&mut self) { unsafe { __wbindgen_copy_to_typed_array( self.contents.as_ptr() as *const u8, self.contents.len() * mem::size_of::(), self.js.idx, ); } } } impl Deref for MutSlice { type Target = [T]; fn deref(&self) -> &[T] { &self.contents } } impl DerefMut for MutSlice { fn deref_mut(&mut self) -> &mut [T] { &mut self.contents } } macro_rules! vectors { ($($t:ty)*) => ($( vectors_internal!($t); vectors_internal!(MaybeUninit<$t>); )*) } macro_rules! vectors_internal { ($t:ty) => { impl WasmDescribeVector for $t { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe_vector() { inform(VECTOR); <$t>::describe(); } } impl VectorIntoWasmAbi for $t { type Abi = WasmSlice; #[inline] fn vector_into_abi(vector: Box<[$t]>) -> WasmSlice { let ptr = vector.as_ptr(); let len = vector.len(); mem::forget(vector); WasmSlice { ptr: ptr.into_abi(), len: len as u32, } } } impl VectorFromWasmAbi for $t { type Abi = WasmSlice; #[inline] unsafe fn vector_from_abi(js: WasmSlice) -> Box<[$t]> { let ptr = <*mut $t>::from_abi(js.ptr); let len = js.len as usize; Vec::from_raw_parts(ptr, len, len).into_boxed_slice() } } impl<'a> IntoWasmAbi for &'a [$t] { type Abi = WasmSlice; #[inline] fn into_abi(self) -> WasmSlice { WasmSlice { ptr: self.as_ptr().into_abi(), len: self.len() as u32, } } } impl<'a> OptionIntoWasmAbi for &'a [$t] { #[inline] fn none() -> WasmSlice { null_slice() } } impl<'a> IntoWasmAbi for &'a mut [$t] { type Abi = WasmSlice; #[inline] fn into_abi(self) -> WasmSlice { (&*self).into_abi() } } impl<'a> OptionIntoWasmAbi for &'a mut [$t] { #[inline] fn none() -> WasmSlice { null_slice() } } impl RefFromWasmAbi for [$t] { type Abi = WasmSlice; type Anchor = Box<[$t]>; #[inline] unsafe fn ref_from_abi(js: WasmSlice) -> Box<[$t]> { >::from_abi(js) } } impl RefMutFromWasmAbi for [$t] { type Abi = WasmMutSlice; type Anchor = MutSlice<$t>; #[inline] unsafe fn ref_mut_from_abi(js: WasmMutSlice) -> MutSlice<$t> { let contents = >::from_abi(js.slice); let js = JsValue::from_abi(js.idx); MutSlice { contents, js } } } impl LongRefFromWasmAbi for [$t] { type Abi = WasmSlice; type Anchor = Box<[$t]>; #[inline] unsafe fn long_ref_from_abi(js: WasmSlice) -> Box<[$t]> { Self::ref_from_abi(js) } } }; } vectors! { u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64 } impl WasmDescribeVector for String { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe_vector() { inform(VECTOR); inform(NAMED_EXTERNREF); // Trying to use an actual loop for this breaks the Wasm interpreter. inform(6); inform('s' as u32); inform('t' as u32); inform('r' as u32); inform('i' as u32); inform('n' as u32); inform('g' as u32); } } impl VectorIntoWasmAbi for String { type Abi = as IntoWasmAbi>::Abi; fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi { js_value_vector_into_abi(vector) } } impl VectorFromWasmAbi for String { type Abi = as FromWasmAbi>::Abi; unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]> { js_value_vector_from_abi(js) } } cfg_if! { if #[cfg(feature = "enable-interning")] { #[inline] fn unsafe_get_cached_str(x: &str) -> Option { // This uses 0 for the ptr as an indication that it is a JsValue and not a str. crate::cache::intern::unsafe_get_str(x).map(|x| WasmSlice { ptr: 0, len: x }) } } else { #[inline] fn unsafe_get_cached_str(_x: &str) -> Option { None } } } impl IntoWasmAbi for Vec where Box<[T]>: IntoWasmAbi, { type Abi = as IntoWasmAbi>::Abi; #[inline] fn into_abi(self) -> Self::Abi { self.into_boxed_slice().into_abi() } } impl OptionIntoWasmAbi for Vec where Box<[T]>: IntoWasmAbi, { #[inline] fn none() -> WasmSlice { null_slice() } } impl FromWasmAbi for Vec where Box<[T]>: FromWasmAbi, { type Abi = as FromWasmAbi>::Abi; #[inline] unsafe fn from_abi(js: Self::Abi) -> Self { >::from_abi(js).into() } } impl OptionFromWasmAbi for Vec where Box<[T]>: FromWasmAbi, { #[inline] fn is_none(abi: &WasmSlice) -> bool { abi.ptr == 0 } } impl IntoWasmAbi for String { type Abi = as IntoWasmAbi>::Abi; #[inline] fn into_abi(self) -> Self::Abi { // This is safe because the JsValue is immediately looked up in the heap and // then returned, so use-after-free cannot occur. unsafe_get_cached_str(&self).unwrap_or_else(|| self.into_bytes().into_abi()) } } impl OptionIntoWasmAbi for String { #[inline] fn none() -> Self::Abi { null_slice() } } impl FromWasmAbi for String { type Abi = as FromWasmAbi>::Abi; #[inline] unsafe fn from_abi(js: Self::Abi) -> Self { String::from_utf8_unchecked(>::from_abi(js)) } } impl OptionFromWasmAbi for String { #[inline] fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 } } impl<'a> IntoWasmAbi for &'a str { type Abi = <&'a [u8] as IntoWasmAbi>::Abi; #[inline] fn into_abi(self) -> Self::Abi { // This is safe because the JsValue is immediately looked up in the heap and // then returned, so use-after-free cannot occur. unsafe_get_cached_str(self).unwrap_or_else(|| self.as_bytes().into_abi()) } } impl OptionIntoWasmAbi for &str { #[inline] fn none() -> Self::Abi { null_slice() } } impl RefFromWasmAbi for str { type Abi = <[u8] as RefFromWasmAbi>::Abi; type Anchor = Box; #[inline] unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor { mem::transmute::, Box>(>::from_abi(js)) } } impl LongRefFromWasmAbi for str { type Abi = <[u8] as RefFromWasmAbi>::Abi; type Anchor = Box; #[inline] unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor { Self::ref_from_abi(js) } } impl IntoWasmAbi for Box<[T]> { type Abi = ::Abi; fn into_abi(self) -> Self::Abi { T::vector_into_abi(self) } } impl OptionIntoWasmAbi for Box<[T]> where Self: IntoWasmAbi, { fn none() -> WasmSlice { null_slice() } } impl FromWasmAbi for Box<[T]> { type Abi = ::Abi; unsafe fn from_abi(js: Self::Abi) -> Self { T::vector_from_abi(js) } } impl OptionFromWasmAbi for Box<[T]> where Self: FromWasmAbi, { fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 } } impl VectorIntoWasmAbi for JsValue { type Abi = WasmSlice; #[inline] fn vector_into_abi(vector: Box<[Self]>) -> WasmSlice { let ptr = vector.as_ptr(); let len = vector.len(); mem::forget(vector); WasmSlice { ptr: ptr.into_abi(), len: len as u32, } } } impl VectorFromWasmAbi for JsValue { type Abi = WasmSlice; #[inline] unsafe fn vector_from_abi(js: WasmSlice) -> Box<[Self]> { let ptr = <*mut JsValue>::from_abi(js.ptr); let len = js.len as usize; Vec::from_raw_parts(ptr, len, len).into_boxed_slice() } } impl VectorIntoWasmAbi for T where T: JsObject, { type Abi = WasmSlice; #[inline] fn vector_into_abi(vector: Box<[T]>) -> WasmSlice { let ptr = vector.as_ptr(); let len = vector.len(); mem::forget(vector); WasmSlice { ptr: ptr.into_abi(), len: len as u32, } } } impl VectorFromWasmAbi for T where T: JsObject, { type Abi = WasmSlice; #[inline] unsafe fn vector_from_abi(js: WasmSlice) -> Box<[T]> { let ptr = <*mut JsValue>::from_abi(js.ptr); let len = js.len as usize; let vec: Vec = Vec::from_raw_parts(ptr, len, len) .drain(..) .map(|js_value| T::unchecked_from_js(js_value)) .collect(); vec.into_boxed_slice() } } wasm-bindgen-0.2.99/src/convert/traits.rs000064400000000000000000000304151046102023000164260ustar 00000000000000use core::borrow::Borrow; use core::ops::{Deref, DerefMut}; use crate::describe::*; use crate::JsValue; /// A trait for anything that can be converted into a type that can cross the /// Wasm ABI directly, eg `u32` or `f64`. /// /// This is the opposite operation as `FromWasmAbi` and `Ref[Mut]FromWasmAbi`. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait IntoWasmAbi: WasmDescribe { /// The Wasm ABI type that this converts into when crossing the ABI /// boundary. type Abi: WasmAbi; /// Convert `self` into `Self::Abi` so that it can be sent across the wasm /// ABI boundary. fn into_abi(self) -> Self::Abi; } /// A trait for anything that can be recovered by-value from the Wasm ABI /// boundary, eg a Rust `u8` can be recovered from the Wasm ABI `u32` type. /// /// This is the by-value variant of the opposite operation as `IntoWasmAbi`. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait FromWasmAbi: WasmDescribe { /// The Wasm ABI type that this converts from when coming back out from the /// ABI boundary. type Abi: WasmAbi; /// Recover a `Self` from `Self::Abi`. /// /// # Safety /// /// This is only safe to call when -- and implementations may assume that -- /// the supplied `Self::Abi` was previously generated by a call to `::into_abi()` or the moral equivalent in JS. unsafe fn from_abi(js: Self::Abi) -> Self; } /// A trait for anything that can be recovered as some sort of shared reference /// from the Wasm ABI boundary. /// /// This is the shared reference variant of the opposite operation as /// `IntoWasmAbi`. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait RefFromWasmAbi: WasmDescribe { /// The Wasm ABI type references to `Self` are recovered from. type Abi: WasmAbi; /// The type that holds the reference to `Self` for the duration of the /// invocation of the function that has an `&Self` parameter. This is /// required to ensure that the lifetimes don't persist beyond one function /// call, and so that they remain anonymous. type Anchor: Deref; /// Recover a `Self::Anchor` from `Self::Abi`. /// /// # Safety /// /// Same as `FromWasmAbi::from_abi`. unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor; } /// A version of the `RefFromWasmAbi` trait with the additional requirement /// that the reference must remain valid as long as the anchor isn't dropped. /// /// This isn't the case for `JsValue`'s `RefFromWasmAbi` implementation. To /// avoid having to allocate a spot for the `JsValue` on the `JsValue` heap, /// the `JsValue` is instead pushed onto the `JsValue` stack, and popped off /// again after the function that the reference was passed to returns. So, /// `JsValue` has a different `LongRefFromWasmAbi` implementation that behaves /// the same as `FromWasmAbi`, putting the value on the heap. /// /// This is needed for async functions, where the reference needs to be valid /// for the whole length of the `Future`, rather than the initial synchronous /// call. /// /// 'long ref' is short for 'long-lived reference'. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait LongRefFromWasmAbi: WasmDescribe { /// Same as `RefFromWasmAbi::Abi` type Abi: WasmAbi; /// Same as `RefFromWasmAbi::Anchor` type Anchor: Borrow; /// Same as `RefFromWasmAbi::ref_from_abi` unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor; } /// Dual of the `RefFromWasmAbi` trait, except for mutable references. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait RefMutFromWasmAbi: WasmDescribe { /// Same as `RefFromWasmAbi::Abi` type Abi: WasmAbi; /// Same as `RefFromWasmAbi::Anchor` type Anchor: DerefMut; /// Same as `RefFromWasmAbi::ref_from_abi` unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor; } /// Indicates that this type can be passed to JS as `Option`. /// /// This trait is used when implementing `IntoWasmAbi for Option`. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait OptionIntoWasmAbi: IntoWasmAbi { /// Returns an ABI instance indicating "none", which JS will interpret as /// the `None` branch of this option. /// /// It should be guaranteed that the `IntoWasmAbi` can never produce the ABI /// value returned here. fn none() -> Self::Abi; } /// Indicates that this type can be received from JS as `Option`. /// /// This trait is used when implementing `FromWasmAbi for Option`. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait OptionFromWasmAbi: FromWasmAbi { /// Tests whether the argument is a "none" instance. If so it will be /// deserialized as `None`, and otherwise it will be passed to /// `FromWasmAbi`. fn is_none(abi: &Self::Abi) -> bool; } /// A trait for any type which maps to a Wasm primitive type when used in FFI /// (`i32`, `i64`, `f32`, or `f64`). /// /// This is with the exception of `()` (and other zero-sized types), which are /// also allowed because they're ignored: no arguments actually get added. /// /// # Safety /// /// This is an unsafe trait to implement as there's no guarantee the type /// actually maps to a primitive type. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub unsafe trait WasmPrimitive: Default {} unsafe impl WasmPrimitive for u32 {} unsafe impl WasmPrimitive for i32 {} unsafe impl WasmPrimitive for u64 {} unsafe impl WasmPrimitive for i64 {} unsafe impl WasmPrimitive for f32 {} unsafe impl WasmPrimitive for f64 {} unsafe impl WasmPrimitive for () {} /// A trait which represents types that can be passed across the Wasm ABI /// boundary, by being split into multiple Wasm primitive types. /// /// Up to 4 primitives are supported; if you don't want to use all of them, you /// can set the rest to `()`, which will cause them to be ignored. /// /// You need to be careful how many primitives you use, however: /// `Result` uses up 2 primitives to store the error, and so it /// doesn't work if `T` uses more than 2 primitives. /// /// So, if you're adding support for a type that needs 3 or more primitives and /// is able to be returned, you have to add another primitive here. /// /// There's already one type that uses 3 primitives: `&mut [T]`. However, it /// can't be returned anyway, so it doesn't matter that /// `Result<&mut [T], JsValue>` wouldn't work. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait WasmAbi { type Prim1: WasmPrimitive; type Prim2: WasmPrimitive; type Prim3: WasmPrimitive; type Prim4: WasmPrimitive; /// Splits this type up into primitives to be sent over the ABI. fn split(self) -> (Self::Prim1, Self::Prim2, Self::Prim3, Self::Prim4); /// Reconstructs this type from primitives received over the ABI. fn join(prim1: Self::Prim1, prim2: Self::Prim2, prim3: Self::Prim3, prim4: Self::Prim4) -> Self; } /// A trait representing how to interpret the return value of a function for /// the Wasm ABI. /// /// This is very similar to the `IntoWasmAbi` trait and in fact has a blanket /// implementation for all implementors of the `IntoWasmAbi`. The primary use /// case of this trait is to enable functions to return `Result`, interpreting /// an error as "rethrow this to JS" /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait ReturnWasmAbi: WasmDescribe { /// Same as `IntoWasmAbi::Abi` type Abi: WasmAbi; /// Same as `IntoWasmAbi::into_abi`, except that it may throw and never /// return in the case of `Err`. fn return_abi(self) -> Self::Abi; } impl ReturnWasmAbi for T { type Abi = T::Abi; #[inline] fn return_abi(self) -> Self::Abi { self.into_abi() } } use alloc::boxed::Box; use core::marker::Sized; /// Trait for element types to implement IntoWasmAbi for vectors of /// themselves. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait VectorIntoWasmAbi: WasmDescribeVector + Sized { type Abi: WasmAbi; fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi; } /// Trait for element types to implement FromWasmAbi for vectors of /// themselves. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait VectorFromWasmAbi: WasmDescribeVector + Sized { type Abi: WasmAbi; unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]>; } /// A repr(C) struct containing all of the primitives of a `WasmAbi` type, in /// order. /// /// This is used as the return type of imported/exported functions. `WasmAbi` /// types aren't guaranteed to be FFI-safe, so we can't return them directly: /// instead we return this. /// /// If all but one of the primitives is `()`, this corresponds to returning the /// remaining primitive directly, otherwise a return pointer is used. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. #[repr(C)] pub struct WasmRet { prim1: T::Prim1, prim2: T::Prim2, prim3: T::Prim3, prim4: T::Prim4, } impl From for WasmRet { fn from(value: T) -> Self { let (prim1, prim2, prim3, prim4) = value.split(); Self { prim1, prim2, prim3, prim4, } } } // Ideally this'd just be an `Into` implementation, but unfortunately that // doesn't work because of the orphan rule. impl WasmRet { /// Joins the components of this `WasmRet` back into the type they represent. pub fn join(self) -> T { T::join(self.prim1, self.prim2, self.prim3, self.prim4) } } /// [`TryFromJsValue`] is a trait for converting a JavaScript value ([`JsValue`]) /// into a Rust type. It is used by the [`wasm_bindgen`](wasm_bindgen_macro::wasm_bindgen) /// proc-macro to allow conversion to user types. /// /// Types implementing this trait must specify their conversion logic from /// [`JsValue`] to the Rust type, handling any potential errors that may occur /// during the conversion process. /// /// # ⚠️ Unstable /// /// This is part of the internal [`convert`](crate::convert) module, **no /// stability guarantees** are provided. Use at your own risk. See its /// documentation for more details. pub trait TryFromJsValue: Sized { /// The type returned in the event of a conversion error. type Error; /// Performs the conversion. fn try_from_js_value(value: JsValue) -> Result; } wasm-bindgen-0.2.99/src/describe.rs000064400000000000000000000120461046102023000152200ustar 00000000000000//! This is an internal module, no stability guarantees are provided. Use at //! your own risk. #![doc(hidden)] use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use core::{mem::MaybeUninit, ptr::NonNull}; use crate::{Clamped, JsError, JsObject, JsValue}; use cfg_if::cfg_if; macro_rules! tys { ($($a:ident)*) => (tys! { @ ($($a)*) 0 }); (@ () $v:expr) => {}; (@ ($a:ident $($b:ident)*) $v:expr) => { pub const $a: u32 = $v; tys!(@ ($($b)*) $v+1); } } // NB: this list must be kept in sync with `crates/cli-support/src/descriptor.rs` tys! { I8 U8 I16 U16 I32 U32 I64 U64 I128 U128 F32 F64 BOOLEAN FUNCTION CLOSURE CACHED_STRING STRING REF REFMUT LONGREF SLICE VECTOR EXTERNREF NAMED_EXTERNREF ENUM STRING_ENUM RUST_STRUCT CHAR OPTIONAL RESULT UNIT CLAMPED NONNULL } #[inline(always)] // see the wasm-interpreter crate #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] pub fn inform(a: u32) { unsafe { super::__wbindgen_describe(a) } } pub trait WasmDescribe { fn describe(); } /// Trait for element types to implement WasmDescribe for vectors of /// themselves. pub trait WasmDescribeVector { fn describe_vector(); } macro_rules! simple { ($($t:ident => $d:ident)*) => ($( impl WasmDescribe for $t { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform($d) } } )*) } simple! { i8 => I8 u8 => U8 i16 => I16 u16 => U16 i32 => I32 u32 => U32 i64 => I64 u64 => U64 i128 => I128 u128 => U128 isize => I32 usize => U32 f32 => F32 f64 => F64 bool => BOOLEAN char => CHAR JsValue => EXTERNREF } cfg_if! { if #[cfg(feature = "enable-interning")] { simple! { str => CACHED_STRING } } else { simple! { str => STRING } } } impl WasmDescribe for *const T { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(U32) } } impl WasmDescribe for *mut T { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(U32) } } impl WasmDescribe for NonNull { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(NONNULL) } } impl WasmDescribe for [T] { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(SLICE); T::describe(); } } impl WasmDescribe for &T { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(REF); T::describe(); } } impl WasmDescribe for &mut T { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(REFMUT); T::describe(); } } cfg_if! { if #[cfg(feature = "enable-interning")] { simple! { String => CACHED_STRING } } else { simple! { String => STRING } } } impl WasmDescribeVector for JsValue { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe_vector() { inform(VECTOR); JsValue::describe(); } } impl WasmDescribeVector for T { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe_vector() { inform(VECTOR); T::describe(); } } impl WasmDescribe for Box<[T]> { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { T::describe_vector(); } } impl WasmDescribe for Vec where Box<[T]>: WasmDescribe, { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { >::describe(); } } impl WasmDescribe for Option { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(OPTIONAL); T::describe(); } } impl WasmDescribe for () { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(UNIT) } } impl> WasmDescribe for Result { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(RESULT); T::describe(); } } impl WasmDescribe for MaybeUninit { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { T::describe(); } } impl WasmDescribe for Clamped { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { inform(CLAMPED); T::describe(); } } impl WasmDescribe for JsError { #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] fn describe() { JsValue::describe(); } } wasm-bindgen-0.2.99/src/externref.rs000064400000000000000000000125031046102023000154400ustar 00000000000000use crate::JsValue; use alloc::slice; use alloc::vec::Vec; use core::cell::Cell; use core::cmp::max; externs! { #[link(wasm_import_module = "__wbindgen_externref_xform__")] extern "C" { fn __wbindgen_externref_table_grow(delta: usize) -> i32; fn __wbindgen_externref_table_set_null(idx: usize) -> (); } } pub struct Slab { data: Vec, head: usize, base: usize, } impl Slab { fn new() -> Slab { Slab { data: Vec::new(), head: 0, base: 0, } } fn alloc(&mut self) -> usize { let ret = self.head; if ret == self.data.len() { let curr_len = self.data.len(); if curr_len == self.data.capacity() { let extra = max(128, curr_len); let r = unsafe { __wbindgen_externref_table_grow(extra) }; if r == -1 { internal_error("table grow failure") } if self.base == 0 { self.base = r as usize; } else if self.base + self.data.len() != r as usize { internal_error("someone else allocated table entries?") } if self.data.try_reserve_exact(extra).is_err() { internal_error("allocation failure"); } } // custom condition to ensure `push` below doesn't call `reserve` in // optimized builds which pulls in lots of panic infrastructure if self.data.len() >= self.data.capacity() { internal_error("push should be infallible now") } self.data.push(ret + 1); } // usage of `get_mut` thwarts panicking infrastructure in optimized // builds match self.data.get_mut(ret) { Some(slot) => self.head = *slot, None => internal_error("ret out of bounds"), } ret + self.base } fn dealloc(&mut self, slot: usize) { if slot < self.base { internal_error("free reserved slot"); } let slot = slot - self.base; // usage of `get_mut` thwarts panicking infrastructure in optimized // builds match self.data.get_mut(slot) { Some(ptr) => { *ptr = self.head; self.head = slot; } None => internal_error("slot out of bounds"), } } fn live_count(&self) -> u32 { let mut free_count = 0; let mut next = self.head; while next < self.data.len() { debug_assert!((free_count as usize) < self.data.len()); free_count += 1; match self.data.get(next) { Some(n) => next = *n, None => internal_error("slot out of bounds"), }; } self.data.len() as u32 - free_count } } fn internal_error(msg: &str) -> ! { cfg_if::cfg_if! { if #[cfg(debug_assertions)] { super::throw_str(msg) } else if #[cfg(feature = "std")] { std::process::abort(); } else if #[cfg(all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") ))] { core::arch::wasm32::unreachable(); } else { unreachable!() } } } // Management of `externref` is always thread local since an `externref` value // can't cross threads in wasm. Indices as a result are always thread-local. #[cfg(feature = "std")] std::thread_local!(static HEAP_SLAB: Cell = Cell::new(Slab::new())); #[cfg(not(feature = "std"))] #[cfg_attr(target_feature = "atomics", thread_local)] static HEAP_SLAB: crate::__rt::LazyCell> = crate::__rt::LazyCell::new(|| Cell::new(Slab::new())); #[no_mangle] pub extern "C" fn __externref_table_alloc() -> usize { HEAP_SLAB .try_with(|slot| { let mut slab = slot.replace(Slab::new()); let ret = slab.alloc(); slot.replace(slab); ret }) .unwrap_or_else(|_| internal_error("tls access failure")) } #[no_mangle] pub extern "C" fn __externref_table_dealloc(idx: usize) { if idx < super::JSIDX_RESERVED as usize { return; } // clear this value from the table so while the table slot is un-allocated // we don't keep around a strong reference to a potentially large object unsafe { __wbindgen_externref_table_set_null(idx); } HEAP_SLAB .try_with(|slot| { let mut slab = slot.replace(Slab::new()); slab.dealloc(idx); slot.replace(slab); }) .unwrap_or_else(|_| internal_error("tls access failure")) } #[no_mangle] pub unsafe extern "C" fn __externref_drop_slice(ptr: *mut JsValue, len: usize) { for slot in slice::from_raw_parts_mut(ptr, len) { __externref_table_dealloc(slot.idx as usize); } } // Implementation of `__wbindgen_externref_heap_live_count` for when we are using // `externref` instead of the JS `heap`. #[no_mangle] pub unsafe extern "C" fn __externref_heap_live_count() -> u32 { HEAP_SLAB .try_with(|slot| { let slab = slot.replace(Slab::new()); let count = slab.live_count(); slot.replace(slab); count }) .unwrap_or_else(|_| internal_error("tls access failure")) } wasm-bindgen-0.2.99/src/lib.rs000064400000000000000000002312261046102023000142110ustar 00000000000000//! Runtime support for the `wasm-bindgen` tool //! //! This crate contains the runtime support necessary for `wasm-bindgen` the //! attribute and tool. Crates pull in the `#[wasm_bindgen]` attribute through //! this crate and this crate also provides JS bindings through the `JsValue` //! interface. #![no_std] #![cfg_attr( wasm_bindgen_unstable_test_coverage, feature(coverage_attribute, allow_internal_unstable), allow(internal_features) )] #![cfg_attr( all(not(feature = "std"), target_feature = "atomics"), feature(thread_local, allow_internal_unstable), allow(internal_features) )] #![allow(coherence_leak_check)] #![doc(html_root_url = "https://docs.rs/wasm-bindgen/0.2")] extern crate alloc; use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use core::convert::TryFrom; use core::marker; use core::mem; use core::ops::{ Add, BitAnd, BitOr, BitXor, Deref, DerefMut, Div, Mul, Neg, Not, Rem, Shl, Shr, Sub, }; use core::ptr::NonNull; use crate::convert::{FromWasmAbi, TryFromJsValue, WasmRet, WasmSlice}; macro_rules! if_std { ($($i:item)*) => ($( #[cfg(feature = "std")] $i )*) } macro_rules! externs { ($(#[$attr:meta])* extern "C" { $(fn $name:ident($($args:tt)*) -> $ret:ty;)* }) => ( #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))] $(#[$attr])* extern "C" { $(fn $name($($args)*) -> $ret;)* } $( #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))] #[allow(unused_variables)] unsafe extern fn $name($($args)*) -> $ret { panic!("function not implemented on non-wasm32 targets") } )* ) } /// A module which is typically glob imported. /// /// ``` /// use wasm_bindgen::prelude::*; /// ``` pub mod prelude { pub use crate::closure::Closure; pub use crate::JsCast; pub use crate::JsValue; pub use crate::UnwrapThrowExt; #[doc(hidden)] pub use wasm_bindgen_macro::__wasm_bindgen_class_marker; pub use wasm_bindgen_macro::wasm_bindgen; pub use crate::JsError; } pub use wasm_bindgen_macro::link_to; pub mod closure; pub mod convert; pub mod describe; mod externref; mod link; mod cast; pub use crate::cast::{JsCast, JsObject}; if_std! { extern crate std; use std::prelude::v1::*; mod cache; pub use cache::intern::{intern, unintern}; } /// Representation of an object owned by JS. /// /// A `JsValue` doesn't actually live in Rust right now but actually in a table /// owned by the `wasm-bindgen` generated JS glue code. Eventually the ownership /// will transfer into Wasm directly and this will likely become more efficient, /// but for now it may be slightly slow. pub struct JsValue { idx: u32, _marker: marker::PhantomData<*mut u8>, // not at all threadsafe } const JSIDX_OFFSET: u32 = 128; // keep in sync with js/mod.rs const JSIDX_UNDEFINED: u32 = JSIDX_OFFSET; const JSIDX_NULL: u32 = JSIDX_OFFSET + 1; const JSIDX_TRUE: u32 = JSIDX_OFFSET + 2; const JSIDX_FALSE: u32 = JSIDX_OFFSET + 3; const JSIDX_RESERVED: u32 = JSIDX_OFFSET + 4; impl JsValue { /// The `null` JS value constant. pub const NULL: JsValue = JsValue::_new(JSIDX_NULL); /// The `undefined` JS value constant. pub const UNDEFINED: JsValue = JsValue::_new(JSIDX_UNDEFINED); /// The `true` JS value constant. pub const TRUE: JsValue = JsValue::_new(JSIDX_TRUE); /// The `false` JS value constant. pub const FALSE: JsValue = JsValue::_new(JSIDX_FALSE); #[inline] const fn _new(idx: u32) -> JsValue { JsValue { idx, _marker: marker::PhantomData, } } /// Creates a new JS value which is a string. /// /// The utf-8 string provided is copied to the JS heap and the string will /// be owned by the JS garbage collector. #[allow(clippy::should_implement_trait)] // cannot fix without breaking change #[inline] pub fn from_str(s: &str) -> JsValue { unsafe { JsValue::_new(__wbindgen_string_new(s.as_ptr(), s.len())) } } /// Creates a new JS value which is a number. /// /// This function creates a JS value representing a number (a heap /// allocated number) and returns a handle to the JS version of it. #[inline] pub fn from_f64(n: f64) -> JsValue { unsafe { JsValue::_new(__wbindgen_number_new(n)) } } /// Creates a new JS value which is a bigint from a string representing a number. /// /// This function creates a JS value representing a bigint (a heap /// allocated large integer) and returns a handle to the JS version of it. #[inline] pub fn bigint_from_str(s: &str) -> JsValue { unsafe { JsValue::_new(__wbindgen_bigint_from_str(s.as_ptr(), s.len())) } } /// Creates a new JS value which is a boolean. /// /// This function creates a JS object representing a boolean (a heap /// allocated boolean) and returns a handle to the JS version of it. #[inline] pub const fn from_bool(b: bool) -> JsValue { if b { JsValue::TRUE } else { JsValue::FALSE } } /// Creates a new JS value representing `undefined`. #[inline] pub const fn undefined() -> JsValue { JsValue::UNDEFINED } /// Creates a new JS value representing `null`. #[inline] pub const fn null() -> JsValue { JsValue::NULL } /// Creates a new JS symbol with the optional description specified. /// /// This function will invoke the `Symbol` constructor in JS and return the /// JS object corresponding to the symbol created. pub fn symbol(description: Option<&str>) -> JsValue { unsafe { match description { Some(description) => JsValue::_new(__wbindgen_symbol_named_new( description.as_ptr(), description.len(), )), None => JsValue::_new(__wbindgen_symbol_anonymous_new()), } } } /// Creates a new `JsValue` from the JSON serialization of the object `t` /// provided. /// /// **This function is deprecated**, due to [creating a dependency cycle in /// some circumstances][dep-cycle-issue]. Use [`serde-wasm-bindgen`] or /// [`gloo_utils::format::JsValueSerdeExt`] instead. /// /// [dep-cycle-issue]: https://github.com/rustwasm/wasm-bindgen/issues/2770 /// [`serde-wasm-bindgen`]: https://docs.rs/serde-wasm-bindgen /// [`gloo_utils::format::JsValueSerdeExt`]: https://docs.rs/gloo-utils/latest/gloo_utils/format/trait.JsValueSerdeExt.html /// /// This function will serialize the provided value `t` to a JSON string, /// send the JSON string to JS, parse it into a JS object, and then return /// a handle to the JS object. This is unlikely to be super speedy so it's /// not recommended for large payloads, but it's a nice to have in some /// situations! /// /// Usage of this API requires activating the `serde-serialize` feature of /// the `wasm-bindgen` crate. /// /// # Errors /// /// Returns any error encountered when serializing `T` into JSON. #[cfg(feature = "serde-serialize")] #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` or `gloo_utils::format::JsValueSerdeExt` instead"] pub fn from_serde(t: &T) -> serde_json::Result where T: serde::ser::Serialize + ?Sized, { let s = serde_json::to_string(t)?; unsafe { Ok(JsValue::_new(__wbindgen_json_parse(s.as_ptr(), s.len()))) } } /// Invokes `JSON.stringify` on this value and then parses the resulting /// JSON into an arbitrary Rust value. /// /// **This function is deprecated**, due to [creating a dependency cycle in /// some circumstances][dep-cycle-issue]. Use [`serde-wasm-bindgen`] or /// [`gloo_utils::format::JsValueSerdeExt`] instead. /// /// [dep-cycle-issue]: https://github.com/rustwasm/wasm-bindgen/issues/2770 /// [`serde-wasm-bindgen`]: https://docs.rs/serde-wasm-bindgen /// [`gloo_utils::format::JsValueSerdeExt`]: https://docs.rs/gloo-utils/latest/gloo_utils/format/trait.JsValueSerdeExt.html /// /// This function will first call `JSON.stringify` on the `JsValue` itself. /// The resulting string is then passed into Rust which then parses it as /// JSON into the resulting value. /// /// Usage of this API requires activating the `serde-serialize` feature of /// the `wasm-bindgen` crate. /// /// # Errors /// /// Returns any error encountered when parsing the JSON into a `T`. #[cfg(feature = "serde-serialize")] #[deprecated = "causes dependency cycles, use `serde-wasm-bindgen` or `gloo_utils::format::JsValueSerdeExt` instead"] pub fn into_serde(&self) -> serde_json::Result where T: for<'a> serde::de::Deserialize<'a>, { unsafe { let ret = __wbindgen_json_serialize(self.idx); let s = String::from_abi(ret); serde_json::from_str(&s) } } /// Returns the `f64` value of this JS value if it's an instance of a /// number. /// /// If this JS value is not an instance of a number then this returns /// `None`. #[inline] pub fn as_f64(&self) -> Option { unsafe { __wbindgen_number_get(self.idx).join() } } /// Tests whether this JS value is a JS string. #[inline] pub fn is_string(&self) -> bool { unsafe { __wbindgen_is_string(self.idx) == 1 } } /// If this JS value is a string value, this function copies the JS string /// value into Wasm linear memory, encoded as UTF-8, and returns it as a /// Rust `String`. /// /// To avoid the copying and re-encoding, consider the /// `JsString::try_from()` function from [js-sys](https://docs.rs/js-sys) /// instead. /// /// If this JS value is not an instance of a string or if it's not valid /// utf-8 then this returns `None`. /// /// # UTF-16 vs UTF-8 /// /// JavaScript strings in general are encoded as UTF-16, but Rust strings /// are encoded as UTF-8. This can cause the Rust string to look a bit /// different than the JS string sometimes. For more details see the /// [documentation about the `str` type][caveats] which contains a few /// caveats about the encodings. /// /// [caveats]: https://rustwasm.github.io/docs/wasm-bindgen/reference/types/str.html #[inline] pub fn as_string(&self) -> Option { unsafe { FromWasmAbi::from_abi(__wbindgen_string_get(self.idx)) } } /// Returns the `bool` value of this JS value if it's an instance of a /// boolean. /// /// If this JS value is not an instance of a boolean then this returns /// `None`. #[inline] pub fn as_bool(&self) -> Option { unsafe { match __wbindgen_boolean_get(self.idx) { 0 => Some(false), 1 => Some(true), _ => None, } } } /// Tests whether this JS value is `null` #[inline] pub fn is_null(&self) -> bool { unsafe { __wbindgen_is_null(self.idx) == 1 } } /// Tests whether this JS value is `undefined` #[inline] pub fn is_undefined(&self) -> bool { unsafe { __wbindgen_is_undefined(self.idx) == 1 } } /// Tests whether the type of this JS value is `symbol` #[inline] pub fn is_symbol(&self) -> bool { unsafe { __wbindgen_is_symbol(self.idx) == 1 } } /// Tests whether `typeof self == "object" && self !== null`. #[inline] pub fn is_object(&self) -> bool { unsafe { __wbindgen_is_object(self.idx) == 1 } } /// Tests whether this JS value is an instance of Array. #[inline] pub fn is_array(&self) -> bool { unsafe { __wbindgen_is_array(self.idx) == 1 } } /// Tests whether the type of this JS value is `function`. #[inline] pub fn is_function(&self) -> bool { unsafe { __wbindgen_is_function(self.idx) == 1 } } /// Tests whether the type of this JS value is `bigint`. #[inline] pub fn is_bigint(&self) -> bool { unsafe { __wbindgen_is_bigint(self.idx) == 1 } } /// Applies the unary `typeof` JS operator on a `JsValue`. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) #[inline] pub fn js_typeof(&self) -> JsValue { unsafe { JsValue::_new(__wbindgen_typeof(self.idx)) } } /// Applies the binary `in` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) #[inline] pub fn js_in(&self, obj: &JsValue) -> bool { unsafe { __wbindgen_in(self.idx, obj.idx) == 1 } } /// Tests whether the value is ["truthy"]. /// /// ["truthy"]: https://developer.mozilla.org/en-US/docs/Glossary/Truthy #[inline] pub fn is_truthy(&self) -> bool { !self.is_falsy() } /// Tests whether the value is ["falsy"]. /// /// ["falsy"]: https://developer.mozilla.org/en-US/docs/Glossary/Falsy #[inline] pub fn is_falsy(&self) -> bool { unsafe { __wbindgen_is_falsy(self.idx) == 1 } } /// Get a string representation of the JavaScript object for debugging. #[cfg(feature = "std")] fn as_debug_string(&self) -> String { unsafe { let mut ret = [0; 2]; __wbindgen_debug_string(&mut ret, self.idx); let data = Vec::from_raw_parts(ret[0] as *mut u8, ret[1], ret[1]); String::from_utf8_unchecked(data) } } /// Compare two `JsValue`s for equality, using the `==` operator in JS. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Equality) #[inline] pub fn loose_eq(&self, other: &Self) -> bool { unsafe { __wbindgen_jsval_loose_eq(self.idx, other.idx) != 0 } } /// Applies the unary `~` JS operator on a `JsValue`. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_NOT) #[inline] pub fn bit_not(&self) -> JsValue { unsafe { JsValue::_new(__wbindgen_bit_not(self.idx)) } } /// Applies the binary `>>>` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unsigned_right_shift) #[inline] pub fn unsigned_shr(&self, rhs: &Self) -> u32 { unsafe { __wbindgen_unsigned_shr(self.idx, rhs.idx) } } /// Applies the binary `/` JS operator on two `JsValue`s, catching and returning any `RangeError` thrown. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) #[inline] pub fn checked_div(&self, rhs: &Self) -> Self { unsafe { JsValue::_new(__wbindgen_checked_div(self.idx, rhs.idx)) } } /// Applies the binary `**` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Exponentiation) #[inline] pub fn pow(&self, rhs: &Self) -> Self { unsafe { JsValue::_new(__wbindgen_pow(self.idx, rhs.idx)) } } /// Applies the binary `<` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than) #[inline] pub fn lt(&self, other: &Self) -> bool { unsafe { __wbindgen_lt(self.idx, other.idx) == 1 } } /// Applies the binary `<=` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Less_than_or_equal) #[inline] pub fn le(&self, other: &Self) -> bool { unsafe { __wbindgen_le(self.idx, other.idx) == 1 } } /// Applies the binary `>=` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than_or_equal) #[inline] pub fn ge(&self, other: &Self) -> bool { unsafe { __wbindgen_ge(self.idx, other.idx) == 1 } } /// Applies the binary `>` JS operator on the two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Greater_than) #[inline] pub fn gt(&self, other: &Self) -> bool { unsafe { __wbindgen_gt(self.idx, other.idx) == 1 } } /// Applies the unary `+` JS operator on a `JsValue`. Can throw. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) #[inline] pub fn unchecked_into_f64(&self) -> f64 { unsafe { __wbindgen_as_number(self.idx) } } } impl PartialEq for JsValue { /// Compares two `JsValue`s for equality, using the `===` operator in JS. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Strict_equality) #[inline] fn eq(&self, other: &Self) -> bool { unsafe { __wbindgen_jsval_eq(self.idx, other.idx) != 0 } } } impl PartialEq for JsValue { #[inline] fn eq(&self, other: &bool) -> bool { self.as_bool() == Some(*other) } } impl PartialEq for JsValue { #[inline] fn eq(&self, other: &str) -> bool { *self == JsValue::from_str(other) } } impl<'a> PartialEq<&'a str> for JsValue { #[inline] fn eq(&self, other: &&'a str) -> bool { >::eq(self, other) } } impl PartialEq for JsValue { #[inline] fn eq(&self, other: &String) -> bool { >::eq(self, other) } } impl<'a> PartialEq<&'a String> for JsValue { #[inline] fn eq(&self, other: &&'a String) -> bool { >::eq(self, other) } } macro_rules! forward_deref_unop { (impl $imp:ident, $method:ident for $t:ty) => { impl $imp for $t { type Output = <&'static $t as $imp>::Output; #[inline] fn $method(self) -> <&'static $t as $imp>::Output { $imp::$method(&self) } } }; } macro_rules! forward_deref_binop { (impl $imp:ident, $method:ident for $t:ty) => { impl<'a> $imp<$t> for &'a $t { type Output = <&'static $t as $imp<&'static $t>>::Output; #[inline] fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(self, &other) } } impl $imp<&$t> for $t { type Output = <&'static $t as $imp<&'static $t>>::Output; #[inline] fn $method(self, other: &$t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(&self, other) } } impl $imp<$t> for $t { type Output = <&'static $t as $imp<&'static $t>>::Output; #[inline] fn $method(self, other: $t) -> <&'static $t as $imp<&'static $t>>::Output { $imp::$method(&self, &other) } } }; } impl Not for &JsValue { type Output = bool; /// Applies the `!` JS operator on a `JsValue`. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) #[inline] fn not(self) -> Self::Output { JsValue::is_falsy(self) } } forward_deref_unop!(impl Not, not for JsValue); impl TryFrom for f64 { type Error = JsValue; /// Applies the unary `+` JS operator on a `JsValue`. /// Returns the numeric result on success, or the JS error value on error. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) #[inline] fn try_from(val: JsValue) -> Result { f64::try_from(&val) } } impl TryFrom<&JsValue> for f64 { type Error = JsValue; /// Applies the unary `+` JS operator on a `JsValue`. /// Returns the numeric result on success, or the JS error value on error. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus) #[inline] fn try_from(val: &JsValue) -> Result { let jsval = unsafe { JsValue::_new(__wbindgen_try_into_number(val.idx)) }; match jsval.as_f64() { Some(num) => Ok(num), None => Err(jsval), } } } impl Neg for &JsValue { type Output = JsValue; /// Applies the unary `-` JS operator on a `JsValue`. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_negation) #[inline] fn neg(self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_neg(self.idx)) } } } forward_deref_unop!(impl Neg, neg for JsValue); impl BitAnd for &JsValue { type Output = JsValue; /// Applies the binary `&` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_AND) #[inline] fn bitand(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_bit_and(self.idx, rhs.idx)) } } } forward_deref_binop!(impl BitAnd, bitand for JsValue); impl BitOr for &JsValue { type Output = JsValue; /// Applies the binary `|` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_OR) #[inline] fn bitor(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_bit_or(self.idx, rhs.idx)) } } } forward_deref_binop!(impl BitOr, bitor for JsValue); impl BitXor for &JsValue { type Output = JsValue; /// Applies the binary `^` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_XOR) #[inline] fn bitxor(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_bit_xor(self.idx, rhs.idx)) } } } forward_deref_binop!(impl BitXor, bitxor for JsValue); impl Shl for &JsValue { type Output = JsValue; /// Applies the binary `<<` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift) #[inline] fn shl(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_shl(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Shl, shl for JsValue); impl Shr for &JsValue { type Output = JsValue; /// Applies the binary `>>` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift) #[inline] fn shr(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_shr(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Shr, shr for JsValue); impl Add for &JsValue { type Output = JsValue; /// Applies the binary `+` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Addition) #[inline] fn add(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_add(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Add, add for JsValue); impl Sub for &JsValue { type Output = JsValue; /// Applies the binary `-` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Subtraction) #[inline] fn sub(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_sub(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Sub, sub for JsValue); impl Div for &JsValue { type Output = JsValue; /// Applies the binary `/` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Division) #[inline] fn div(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_div(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Div, div for JsValue); impl Mul for &JsValue { type Output = JsValue; /// Applies the binary `*` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Multiplication) #[inline] fn mul(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_mul(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Mul, mul for JsValue); impl Rem for &JsValue { type Output = JsValue; /// Applies the binary `%` JS operator on two `JsValue`s. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder) #[inline] fn rem(self, rhs: Self) -> Self::Output { unsafe { JsValue::_new(__wbindgen_rem(self.idx, rhs.idx)) } } } forward_deref_binop!(impl Rem, rem for JsValue); impl<'a> From<&'a str> for JsValue { #[inline] fn from(s: &'a str) -> JsValue { JsValue::from_str(s) } } impl From<*mut T> for JsValue { #[inline] fn from(s: *mut T) -> JsValue { JsValue::from(s as usize) } } impl From<*const T> for JsValue { #[inline] fn from(s: *const T) -> JsValue { JsValue::from(s as usize) } } impl From> for JsValue { #[inline] fn from(s: NonNull) -> JsValue { JsValue::from(s.as_ptr() as usize) } } impl<'a> From<&'a String> for JsValue { #[inline] fn from(s: &'a String) -> JsValue { JsValue::from_str(s) } } impl From for JsValue { #[inline] fn from(s: String) -> JsValue { JsValue::from_str(&s) } } impl TryFrom for String { type Error = JsValue; fn try_from(value: JsValue) -> Result { match value.as_string() { Some(s) => Ok(s), None => Err(value), } } } impl TryFromJsValue for String { type Error = JsValue; fn try_from_js_value(value: JsValue) -> Result { match value.as_string() { Some(s) => Ok(s), None => Err(value), } } } impl From for JsValue { #[inline] fn from(s: bool) -> JsValue { JsValue::from_bool(s) } } impl<'a, T> From<&'a T> for JsValue where T: JsCast, { #[inline] fn from(s: &'a T) -> JsValue { s.as_ref().clone() } } impl From> for JsValue where JsValue: From, { #[inline] fn from(s: Option) -> JsValue { match s { Some(s) => s.into(), None => JsValue::undefined(), } } } impl JsCast for JsValue { // everything is a `JsValue`! #[inline] fn instanceof(_val: &JsValue) -> bool { true } #[inline] fn unchecked_from_js(val: JsValue) -> Self { val } #[inline] fn unchecked_from_js_ref(val: &JsValue) -> &Self { val } } impl AsRef for JsValue { #[inline] fn as_ref(&self) -> &JsValue { self } } macro_rules! numbers { ($($n:ident)*) => ($( impl PartialEq<$n> for JsValue { #[inline] fn eq(&self, other: &$n) -> bool { self.as_f64() == Some(f64::from(*other)) } } impl From<$n> for JsValue { #[inline] fn from(n: $n) -> JsValue { JsValue::from_f64(n.into()) } } )*) } numbers! { i8 u8 i16 u16 i32 u32 f32 f64 } macro_rules! big_numbers { (|$arg:ident|, $($n:ident = $handle:expr,)*) => ($( impl PartialEq<$n> for JsValue { #[inline] fn eq(&self, other: &$n) -> bool { self == &JsValue::from(*other) } } impl From<$n> for JsValue { #[inline] fn from($arg: $n) -> JsValue { unsafe { JsValue::_new($handle) } } } )*) } fn bigint_get_as_i64(v: &JsValue) -> Option { unsafe { __wbindgen_bigint_get_as_i64(v.idx).join() } } macro_rules! try_from_for_num64 { ($ty:ty) => { impl TryFrom for $ty { type Error = JsValue; #[inline] fn try_from(v: JsValue) -> Result { bigint_get_as_i64(&v) // Reinterpret bits; ABI-wise this is safe to do and allows us to avoid // having separate intrinsics per signed/unsigned types. .map(|as_i64| as_i64 as Self) // Double-check that we didn't truncate the bigint to 64 bits. .filter(|as_self| v == *as_self) // Not a bigint or not in range. .ok_or(v) } } }; } try_from_for_num64!(i64); try_from_for_num64!(u64); macro_rules! try_from_for_num128 { ($ty:ty, $hi_ty:ty) => { impl TryFrom for $ty { type Error = JsValue; #[inline] fn try_from(v: JsValue) -> Result { // Truncate the bigint to 64 bits, this will give us the lower part. let lo = match bigint_get_as_i64(&v) { // The lower part must be interpreted as unsigned in both i128 and u128. Some(lo) => lo as u64, // Not a bigint. None => return Err(v), }; // Now we know it's a bigint, so we can safely use `>> 64n` without // worrying about a JS exception on type mismatch. let hi = v >> JsValue::from(64_u64); // The high part is the one we want checked against a 64-bit range. // If it fits, then our original number is in the 128-bit range. let hi = <$hi_ty>::try_from(hi)?; Ok(Self::from(hi) << 64 | Self::from(lo)) } } }; } try_from_for_num128!(i128, i64); try_from_for_num128!(u128, u64); big_numbers! { |n|, i64 = __wbindgen_bigint_from_i64(n), u64 = __wbindgen_bigint_from_u64(n), i128 = __wbindgen_bigint_from_i128((n >> 64) as i64, n as u64), u128 = __wbindgen_bigint_from_u128((n >> 64) as u64, n as u64), } // `usize` and `isize` have to be treated a bit specially, because we know that // they're 32-bit but the compiler conservatively assumes they might be bigger. // So, we have to manually forward to the `u32`/`i32` versions. impl PartialEq for JsValue { #[inline] fn eq(&self, other: &usize) -> bool { *self == (*other as u32) } } impl From for JsValue { #[inline] fn from(n: usize) -> Self { Self::from(n as u32) } } impl PartialEq for JsValue { #[inline] fn eq(&self, other: &isize) -> bool { *self == (*other as i32) } } impl From for JsValue { #[inline] fn from(n: isize) -> Self { Self::from(n as i32) } } externs! { #[link(wasm_import_module = "__wbindgen_placeholder__")] extern "C" { fn __wbindgen_object_clone_ref(idx: u32) -> u32; fn __wbindgen_object_drop_ref(idx: u32) -> (); fn __wbindgen_string_new(ptr: *const u8, len: usize) -> u32; fn __wbindgen_number_new(f: f64) -> u32; fn __wbindgen_bigint_from_str(ptr: *const u8, len: usize) -> u32; fn __wbindgen_bigint_from_i64(n: i64) -> u32; fn __wbindgen_bigint_from_u64(n: u64) -> u32; fn __wbindgen_bigint_from_i128(hi: i64, lo: u64) -> u32; fn __wbindgen_bigint_from_u128(hi: u64, lo: u64) -> u32; fn __wbindgen_symbol_named_new(ptr: *const u8, len: usize) -> u32; fn __wbindgen_symbol_anonymous_new() -> u32; fn __wbindgen_externref_heap_live_count() -> u32; fn __wbindgen_is_null(idx: u32) -> u32; fn __wbindgen_is_undefined(idx: u32) -> u32; fn __wbindgen_is_symbol(idx: u32) -> u32; fn __wbindgen_is_object(idx: u32) -> u32; fn __wbindgen_is_array(idx: u32) -> u32; fn __wbindgen_is_function(idx: u32) -> u32; fn __wbindgen_is_string(idx: u32) -> u32; fn __wbindgen_is_bigint(idx: u32) -> u32; fn __wbindgen_typeof(idx: u32) -> u32; fn __wbindgen_in(prop: u32, obj: u32) -> u32; fn __wbindgen_is_falsy(idx: u32) -> u32; fn __wbindgen_as_number(idx: u32) -> f64; fn __wbindgen_try_into_number(idx: u32) -> u32; fn __wbindgen_neg(idx: u32) -> u32; fn __wbindgen_bit_and(a: u32, b: u32) -> u32; fn __wbindgen_bit_or(a: u32, b: u32) -> u32; fn __wbindgen_bit_xor(a: u32, b: u32) -> u32; fn __wbindgen_bit_not(idx: u32) -> u32; fn __wbindgen_shl(a: u32, b: u32) -> u32; fn __wbindgen_shr(a: u32, b: u32) -> u32; fn __wbindgen_unsigned_shr(a: u32, b: u32) -> u32; fn __wbindgen_add(a: u32, b: u32) -> u32; fn __wbindgen_sub(a: u32, b: u32) -> u32; fn __wbindgen_div(a: u32, b: u32) -> u32; fn __wbindgen_checked_div(a: u32, b: u32) -> u32; fn __wbindgen_mul(a: u32, b: u32) -> u32; fn __wbindgen_rem(a: u32, b: u32) -> u32; fn __wbindgen_pow(a: u32, b: u32) -> u32; fn __wbindgen_lt(a: u32, b: u32) -> u32; fn __wbindgen_le(a: u32, b: u32) -> u32; fn __wbindgen_ge(a: u32, b: u32) -> u32; fn __wbindgen_gt(a: u32, b: u32) -> u32; fn __wbindgen_number_get(idx: u32) -> WasmRet>; fn __wbindgen_boolean_get(idx: u32) -> u32; fn __wbindgen_string_get(idx: u32) -> WasmSlice; fn __wbindgen_bigint_get_as_i64(idx: u32) -> WasmRet>; fn __wbindgen_debug_string(ret: *mut [usize; 2], idx: u32) -> (); fn __wbindgen_throw(a: *const u8, b: usize) -> !; fn __wbindgen_rethrow(a: u32) -> !; fn __wbindgen_error_new(a: *const u8, b: usize) -> u32; fn __wbindgen_cb_drop(idx: u32) -> u32; fn __wbindgen_describe(v: u32) -> (); fn __wbindgen_describe_closure(a: u32, b: u32, c: u32) -> u32; fn __wbindgen_json_parse(ptr: *const u8, len: usize) -> u32; fn __wbindgen_json_serialize(idx: u32) -> WasmSlice; fn __wbindgen_jsval_eq(a: u32, b: u32) -> u32; fn __wbindgen_jsval_loose_eq(a: u32, b: u32) -> u32; fn __wbindgen_copy_to_typed_array(ptr: *const u8, len: usize, idx: u32) -> (); fn __wbindgen_uint8_array_new(ptr: *mut u8, len: usize) -> u32; fn __wbindgen_uint8_clamped_array_new(ptr: *mut u8, len: usize) -> u32; fn __wbindgen_uint16_array_new(ptr: *mut u16, len: usize) -> u32; fn __wbindgen_uint32_array_new(ptr: *mut u32, len: usize) -> u32; fn __wbindgen_biguint64_array_new(ptr: *mut u64, len: usize) -> u32; fn __wbindgen_int8_array_new(ptr: *mut i8, len: usize) -> u32; fn __wbindgen_int16_array_new(ptr: *mut i16, len: usize) -> u32; fn __wbindgen_int32_array_new(ptr: *mut i32, len: usize) -> u32; fn __wbindgen_bigint64_array_new(ptr: *mut i64, len: usize) -> u32; fn __wbindgen_float32_array_new(ptr: *mut f32, len: usize) -> u32; fn __wbindgen_float64_array_new(ptr: *mut f64, len: usize) -> u32; fn __wbindgen_array_new() -> u32; fn __wbindgen_array_push(array: u32, value: u32) -> (); fn __wbindgen_not(idx: u32) -> u32; fn __wbindgen_exports() -> u32; fn __wbindgen_memory() -> u32; fn __wbindgen_module() -> u32; fn __wbindgen_function_table() -> u32; } } impl Clone for JsValue { #[inline] fn clone(&self) -> JsValue { unsafe { let idx = __wbindgen_object_clone_ref(self.idx); JsValue::_new(idx) } } } #[cfg(feature = "std")] impl core::fmt::Debug for JsValue { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "JsValue({})", self.as_debug_string()) } } #[cfg(not(feature = "std"))] impl core::fmt::Debug for JsValue { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.write_str("JsValue") } } impl Drop for JsValue { #[inline] fn drop(&mut self) { unsafe { // We definitely should never drop anything in the stack area debug_assert!(self.idx >= JSIDX_OFFSET, "free of stack slot {}", self.idx); // Otherwise if we're not dropping one of our reserved values, // actually call the intrinsic. See #1054 for eventually removing // this branch. if self.idx >= JSIDX_RESERVED { __wbindgen_object_drop_ref(self.idx); } } } } impl Default for JsValue { fn default() -> Self { Self::UNDEFINED } } /// Wrapper type for imported statics. /// /// This type is used whenever a `static` is imported from a JS module, for /// example this import: /// /// ```ignore /// #[wasm_bindgen] /// extern "C" { /// static console: JsValue; /// } /// ``` /// /// will generate in Rust a value that looks like: /// /// ```ignore /// static console: JsStatic = ...; /// ``` /// /// This type implements `Deref` to the inner type so it's typically used as if /// it were `&T`. #[cfg(feature = "std")] #[deprecated = "use with `#[wasm_bindgen(thread_local_v2)]` instead"] pub struct JsStatic { #[doc(hidden)] pub __inner: &'static std::thread::LocalKey, } #[cfg(feature = "std")] #[allow(deprecated)] #[cfg(not(target_feature = "atomics"))] impl Deref for JsStatic { type Target = T; fn deref(&self) -> &T { unsafe { self.__inner.with(|ptr| &*(ptr as *const T)) } } } /// Wrapper type for imported statics. /// /// This type is used whenever a `static` is imported from a JS module, for /// example this import: /// /// ```ignore /// #[wasm_bindgen] /// extern "C" { /// #[wasm_bindgen(thread_local_v2)] /// static console: JsValue; /// } /// ``` /// /// will generate in Rust a value that looks like: /// /// ```ignore /// static console: JsThreadLocal = ...; /// ``` pub struct JsThreadLocal { #[doc(hidden)] #[cfg(feature = "std")] pub __inner: &'static std::thread::LocalKey, #[doc(hidden)] #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] pub __inner: &'static __rt::LazyCell, #[doc(hidden)] #[cfg(all(not(feature = "std"), target_feature = "atomics"))] pub __inner: fn() -> *const T, } impl JsThreadLocal { pub fn with(&'static self, f: F) -> R where F: FnOnce(&T) -> R, { #[cfg(feature = "std")] return self.__inner.with(f); #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] return f(self.__inner); #[cfg(all(not(feature = "std"), target_feature = "atomics"))] f(unsafe { &*(self.__inner)() }) } } #[cold] #[inline(never)] #[deprecated(note = "renamed to `throw_str`")] #[doc(hidden)] pub fn throw(s: &str) -> ! { throw_str(s) } /// Throws a JS exception. /// /// This function will throw a JS exception with the message provided. The /// function will not return as the Wasm stack will be popped when the exception /// is thrown. /// /// Note that it is very easy to leak memory with this function because this /// function, unlike `panic!` on other platforms, **will not run destructors**. /// It's recommended to return a `Result` where possible to avoid the worry of /// leaks. #[cold] #[inline(never)] pub fn throw_str(s: &str) -> ! { unsafe { __wbindgen_throw(s.as_ptr(), s.len()); } } /// Rethrow a JS exception /// /// This function will throw a JS exception with the JS value provided. This /// function will not return and the Wasm stack will be popped until the point /// of entry of Wasm itself. /// /// Note that it is very easy to leak memory with this function because this /// function, unlike `panic!` on other platforms, **will not run destructors**. /// It's recommended to return a `Result` where possible to avoid the worry of /// leaks. #[cold] #[inline(never)] pub fn throw_val(s: JsValue) -> ! { unsafe { let idx = s.idx; mem::forget(s); __wbindgen_rethrow(idx); } } /// Get the count of live `externref`s / `JsValue`s in `wasm-bindgen`'s heap. /// /// ## Usage /// /// This is intended for debugging and writing tests. /// /// To write a test that asserts against unnecessarily keeping `anref`s / /// `JsValue`s alive: /// /// * get an initial live count, /// /// * perform some series of operations or function calls that should clean up /// after themselves, and should not keep holding onto `externref`s / `JsValue`s /// after completion, /// /// * get the final live count, /// /// * and assert that the initial and final counts are the same. /// /// ## What is Counted /// /// Note that this only counts the *owned* `externref`s / `JsValue`s that end up in /// `wasm-bindgen`'s heap. It does not count borrowed `externref`s / `JsValue`s /// that are on its stack. /// /// For example, these `JsValue`s are accounted for: /// /// ```ignore /// #[wasm_bindgen] /// pub fn my_function(this_is_counted: JsValue) { /// let also_counted = JsValue::from_str("hi"); /// assert!(wasm_bindgen::externref_heap_live_count() >= 2); /// } /// ``` /// /// While this borrowed `JsValue` ends up on the stack, not the heap, and /// therefore is not accounted for: /// /// ```ignore /// #[wasm_bindgen] /// pub fn my_other_function(this_is_not_counted: &JsValue) { /// // ... /// } /// ``` pub fn externref_heap_live_count() -> u32 { unsafe { __wbindgen_externref_heap_live_count() } } #[doc(hidden)] pub fn anyref_heap_live_count() -> u32 { externref_heap_live_count() } /// An extension trait for `Option` and `Result` for unwrapping the `T` /// value, or throwing a JS error if it is not available. /// /// These methods should have a smaller code size footprint than the normal /// `Option::unwrap` and `Option::expect` methods, but they are specific to /// working with Wasm and JS. /// /// On non-wasm32 targets, defaults to the normal unwrap/expect calls. /// /// # Example /// /// ``` /// use wasm_bindgen::prelude::*; /// /// // If the value is `Option::Some` or `Result::Ok`, then we just get the /// // contained `T` value. /// let x = Some(42); /// assert_eq!(x.unwrap_throw(), 42); /// /// let y: Option = None; /// /// // This call would throw an error to JS! /// // /// // y.unwrap_throw() /// // /// // And this call would throw an error to JS with a custom error message! /// // /// // y.expect_throw("woopsie daisy!") /// ``` pub trait UnwrapThrowExt: Sized { /// Unwrap this `Option` or `Result`, but instead of panicking on failure, /// throw an exception to JavaScript. #[cfg_attr( any( debug_assertions, not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))) ), track_caller )] fn unwrap_throw(self) -> T { if cfg!(all( debug_assertions, all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") ) )) { let loc = core::panic::Location::caller(); let msg = alloc::format!( "called `{}::unwrap_throw()` ({}:{}:{})", core::any::type_name::(), loc.file(), loc.line(), loc.column() ); self.expect_throw(&msg) } else { self.expect_throw("called `unwrap_throw()`") } } /// Unwrap this container's `T` value, or throw an error to JS with the /// given message if the `T` value is unavailable (e.g. an `Option` is /// `None`). #[cfg_attr( any( debug_assertions, not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))) ), track_caller )] fn expect_throw(self, message: &str) -> T; } impl UnwrapThrowExt for Option { fn unwrap_throw(self) -> T { const MSG: &str = "called `Option::unwrap_throw()` on a `None` value"; if cfg!(all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") )) { if let Some(val) = self { val } else if cfg!(debug_assertions) { let loc = core::panic::Location::caller(); let msg = alloc::format!("{} ({}:{}:{})", MSG, loc.file(), loc.line(), loc.column(),); throw_str(&msg) } else { throw_str(MSG) } } else { self.expect(MSG) } } fn expect_throw(self, message: &str) -> T { if cfg!(all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") )) { if let Some(val) = self { val } else if cfg!(debug_assertions) { let loc = core::panic::Location::caller(); let msg = alloc::format!( "{} ({}:{}:{})", message, loc.file(), loc.line(), loc.column(), ); throw_str(&msg) } else { throw_str(message) } } else { self.expect(message) } } } impl UnwrapThrowExt for Result where E: core::fmt::Debug, { fn unwrap_throw(self) -> T { const MSG: &str = "called `Result::unwrap_throw()` on an `Err` value"; if cfg!(all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") )) { match self { Ok(val) => val, Err(err) => { if cfg!(debug_assertions) { let loc = core::panic::Location::caller(); let msg = alloc::format!( "{} ({}:{}:{}): {:?}", MSG, loc.file(), loc.line(), loc.column(), err ); throw_str(&msg) } else { throw_str(MSG) } } } } else { self.expect(MSG) } } fn expect_throw(self, message: &str) -> T { if cfg!(all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") )) { match self { Ok(val) => val, Err(err) => { if cfg!(debug_assertions) { let loc = core::panic::Location::caller(); let msg = alloc::format!( "{} ({}:{}:{}): {:?}", message, loc.file(), loc.line(), loc.column(), err ); throw_str(&msg) } else { throw_str(message) } } } } else { self.expect(message) } } } /// Returns a handle to this Wasm instance's `WebAssembly.Module`. /// This is only available when the final Wasm app is built with /// `--target no-modules` or `--target web`. pub fn module() -> JsValue { unsafe { JsValue::_new(__wbindgen_module()) } } /// Returns a handle to this Wasm instance's `WebAssembly.Instance.prototype.exports` pub fn exports() -> JsValue { unsafe { JsValue::_new(__wbindgen_exports()) } } /// Returns a handle to this Wasm instance's `WebAssembly.Memory` pub fn memory() -> JsValue { unsafe { JsValue::_new(__wbindgen_memory()) } } /// Returns a handle to this Wasm instance's `WebAssembly.Table` which is the /// indirect function table used by Rust pub fn function_table() -> JsValue { unsafe { JsValue::_new(__wbindgen_function_table()) } } #[doc(hidden)] pub mod __rt { use crate::JsValue; use core::borrow::{Borrow, BorrowMut}; use core::cell::{Cell, UnsafeCell}; use core::convert::Infallible; use core::mem; use core::ops::{Deref, DerefMut}; #[cfg(all(target_feature = "atomics", not(feature = "std")))] use core::sync::atomic::{AtomicU8, Ordering}; pub extern crate alloc; pub extern crate core; #[cfg(feature = "std")] pub extern crate std; use alloc::alloc::{alloc, dealloc, realloc, Layout}; use alloc::boxed::Box; use alloc::rc::Rc; /// Wrapper around [`::once_cell::unsync::Lazy`] adding some compatibility methods with /// [`std::thread::LocalKey`] and adding `Send + Sync` when `atomics` is not enabled. #[cfg(not(feature = "std"))] pub struct LazyCell T>(::once_cell::unsync::Lazy); #[cfg(all(not(target_feature = "atomics"), not(feature = "std")))] unsafe impl Sync for LazyCell {} #[cfg(all(not(target_feature = "atomics"), not(feature = "std")))] unsafe impl Send for LazyCell {} #[cfg(not(feature = "std"))] impl LazyCell { pub const fn new(init: F) -> LazyCell { Self(::once_cell::unsync::Lazy::new(init)) } } #[cfg(not(feature = "std"))] impl T> LazyCell { pub(crate) fn try_with( &self, f: impl FnOnce(&T) -> R, ) -> Result { Ok(f(&self.0)) } pub fn force(this: &Self) -> &T { &this.0 } } #[cfg(not(feature = "std"))] impl Deref for LazyCell { type Target = T; fn deref(&self) -> &T { ::once_cell::unsync::Lazy::force(&self.0) } } #[cfg(feature = "std")] pub use once_cell::sync::Lazy as LazyLock; #[cfg(all(not(target_feature = "atomics"), not(feature = "std")))] pub use LazyCell as LazyLock; #[cfg(all(target_feature = "atomics", not(feature = "std")))] pub struct LazyLock T> { state: AtomicU8, data: UnsafeCell>, } #[cfg(all(target_feature = "atomics", not(feature = "std")))] enum Data { Value(T), Init(F), } #[cfg(all(target_feature = "atomics", not(feature = "std")))] unsafe impl Sync for LazyLock {} #[cfg(all(target_feature = "atomics", not(feature = "std")))] unsafe impl Send for LazyLock {} #[cfg(all(target_feature = "atomics", not(feature = "std")))] impl LazyLock { const STATE_UNINIT: u8 = 0; const STATE_INITIALIZING: u8 = 1; const STATE_INIT: u8 = 2; pub const fn new(init: F) -> LazyLock { Self { state: AtomicU8::new(Self::STATE_UNINIT), data: UnsafeCell::new(Data::Init(init)), } } } #[cfg(all(target_feature = "atomics", not(feature = "std")))] impl Deref for LazyLock { type Target = T; fn deref(&self) -> &T { let mut state = self.state.load(Ordering::Acquire); loop { match state { Self::STATE_INIT => { let Data::Value(value) = (unsafe { &*self.data.get() }) else { unreachable!() }; return value; } Self::STATE_UNINIT => { if let Err(new_state) = self.state.compare_exchange_weak( Self::STATE_UNINIT, Self::STATE_INITIALIZING, Ordering::Acquire, Ordering::Relaxed, ) { state = new_state; continue; } let data = unsafe { &mut *self.data.get() }; let Data::Init(init) = data else { unreachable!() }; *data = Data::Value(init()); self.state.store(Self::STATE_INIT, Ordering::Release); state = Self::STATE_INIT; } Self::STATE_INITIALIZING => { // TODO: Block here if possible. This would require // detecting if we can in the first place. state = self.state.load(Ordering::Acquire); } _ => unreachable!(), } } } } #[macro_export] #[doc(hidden)] #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] macro_rules! __wbindgen_thread_local { ($wasm_bindgen:tt, $actual_ty:ty) => {{ static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> = $wasm_bindgen::__rt::LazyCell::new(init); $wasm_bindgen::JsThreadLocal { __inner: &_VAL } }}; } #[macro_export] #[doc(hidden)] #[cfg(all(not(feature = "std"), target_feature = "atomics"))] #[allow_internal_unstable(thread_local)] macro_rules! __wbindgen_thread_local { ($wasm_bindgen:tt, $actual_ty:ty) => {{ #[thread_local] static _VAL: $wasm_bindgen::__rt::LazyCell<$actual_ty> = $wasm_bindgen::__rt::LazyCell::new(init); $wasm_bindgen::JsThreadLocal { __inner: || unsafe { $wasm_bindgen::__rt::LazyCell::force(&_VAL) as *const $actual_ty }, } }}; } #[macro_export] #[doc(hidden)] #[cfg(not(wasm_bindgen_unstable_test_coverage))] macro_rules! __wbindgen_coverage { ($item:item) => { $item }; } #[macro_export] #[doc(hidden)] #[cfg(wasm_bindgen_unstable_test_coverage)] #[allow_internal_unstable(coverage_attribute)] macro_rules! __wbindgen_coverage { ($item:item) => { #[coverage(off)] $item }; } #[inline] pub fn assert_not_null(s: *mut T) { if s.is_null() { throw_null(); } } #[cold] #[inline(never)] fn throw_null() -> ! { super::throw_str("null pointer passed to rust"); } /// A vendored version of `RefCell` from the standard library. /// /// Now why, you may ask, would we do that? Surely `RefCell` in libstd is /// quite good. And you're right, it is indeed quite good! Functionally /// nothing more is needed from `RefCell` in the standard library but for /// now this crate is also sort of optimizing for compiled code size. /// /// One major factor to larger binaries in Rust is when a panic happens. /// Panicking in the standard library involves a fair bit of machinery /// (formatting, panic hooks, synchronization, etc). It's all worthwhile if /// you need it but for something like `WasmRefCell` here we don't actually /// need all that! /// /// This is just a wrapper around all Rust objects passed to JS intended to /// guard accidental reentrancy, so this vendored version is intended solely /// to not panic in libstd. Instead when it "panics" it calls our `throw` /// function in this crate which raises an error in JS. pub struct WasmRefCell { borrow: Cell, value: UnsafeCell, } impl WasmRefCell { pub fn new(value: T) -> WasmRefCell where T: Sized, { WasmRefCell { value: UnsafeCell::new(value), borrow: Cell::new(0), } } pub fn get_mut(&mut self) -> &mut T { unsafe { &mut *self.value.get() } } pub fn borrow(&self) -> Ref { unsafe { if self.borrow.get() == usize::MAX { borrow_fail(); } self.borrow.set(self.borrow.get() + 1); Ref { value: &*self.value.get(), borrow: &self.borrow, } } } pub fn borrow_mut(&self) -> RefMut { unsafe { if self.borrow.get() != 0 { borrow_fail(); } self.borrow.set(usize::MAX); RefMut { value: &mut *self.value.get(), borrow: &self.borrow, } } } pub fn into_inner(self) -> T where T: Sized, { self.value.into_inner() } } pub struct Ref<'b, T: ?Sized + 'b> { value: &'b T, borrow: &'b Cell, } impl Deref for Ref<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { self.value } } impl Borrow for Ref<'_, T> { #[inline] fn borrow(&self) -> &T { self.value } } impl Drop for Ref<'_, T> { fn drop(&mut self) { self.borrow.set(self.borrow.get() - 1); } } pub struct RefMut<'b, T: ?Sized + 'b> { value: &'b mut T, borrow: &'b Cell, } impl Deref for RefMut<'_, T> { type Target = T; #[inline] fn deref(&self) -> &T { self.value } } impl DerefMut for RefMut<'_, T> { #[inline] fn deref_mut(&mut self) -> &mut T { self.value } } impl Borrow for RefMut<'_, T> { #[inline] fn borrow(&self) -> &T { self.value } } impl BorrowMut for RefMut<'_, T> { #[inline] fn borrow_mut(&mut self) -> &mut T { self.value } } impl Drop for RefMut<'_, T> { fn drop(&mut self) { self.borrow.set(0); } } fn borrow_fail() -> ! { super::throw_str( "recursive use of an object detected which would lead to \ unsafe aliasing in rust", ); } /// A type that encapsulates an `Rc>` as well as a `Ref` /// to the contents of that `WasmRefCell`. /// /// The `'static` requirement is an unfortunate consequence of how this /// is implemented. pub struct RcRef { // The 'static is a lie. // // We could get away without storing this, since we're in the same module as // `WasmRefCell` and can directly manipulate its `borrow`, but I'm considering // turning it into a wrapper around `std`'s `RefCell` to reduce `unsafe` in // which case that would stop working. This also requires less `unsafe` as is. // // It's important that this goes before `Rc` so that it gets dropped first. ref_: Ref<'static, T>, _rc: Rc>, } impl RcRef { pub fn new(rc: Rc>) -> Self { let ref_ = unsafe { (*Rc::as_ptr(&rc)).borrow() }; Self { _rc: rc, ref_ } } } impl Deref for RcRef { type Target = T; #[inline] fn deref(&self) -> &T { &self.ref_ } } impl Borrow for RcRef { #[inline] fn borrow(&self) -> &T { &self.ref_ } } /// A type that encapsulates an `Rc>` as well as a /// `RefMut` to the contents of that `WasmRefCell`. /// /// The `'static` requirement is an unfortunate consequence of how this /// is implemented. pub struct RcRefMut { ref_: RefMut<'static, T>, _rc: Rc>, } impl RcRefMut { pub fn new(rc: Rc>) -> Self { let ref_ = unsafe { (*Rc::as_ptr(&rc)).borrow_mut() }; Self { _rc: rc, ref_ } } } impl Deref for RcRefMut { type Target = T; #[inline] fn deref(&self) -> &T { &self.ref_ } } impl DerefMut for RcRefMut { #[inline] fn deref_mut(&mut self) -> &mut T { &mut self.ref_ } } impl Borrow for RcRefMut { #[inline] fn borrow(&self) -> &T { &self.ref_ } } impl BorrowMut for RcRefMut { #[inline] fn borrow_mut(&mut self) -> &mut T { &mut self.ref_ } } #[no_mangle] pub extern "C" fn __wbindgen_malloc(size: usize, align: usize) -> *mut u8 { if let Ok(layout) = Layout::from_size_align(size, align) { unsafe { if layout.size() > 0 { let ptr = alloc(layout); if !ptr.is_null() { return ptr; } } else { return align as *mut u8; } } } malloc_failure(); } #[no_mangle] pub unsafe extern "C" fn __wbindgen_realloc( ptr: *mut u8, old_size: usize, new_size: usize, align: usize, ) -> *mut u8 { debug_assert!(old_size > 0); debug_assert!(new_size > 0); if let Ok(layout) = Layout::from_size_align(old_size, align) { let ptr = realloc(ptr, layout, new_size); if !ptr.is_null() { return ptr; } } malloc_failure(); } #[cold] fn malloc_failure() -> ! { cfg_if::cfg_if! { if #[cfg(debug_assertions)] { super::throw_str("invalid malloc request") } else if #[cfg(feature = "std")] { std::process::abort(); } else if #[cfg(all( target_arch = "wasm32", any(target_os = "unknown", target_os = "none") ))] { core::arch::wasm32::unreachable(); } else { unreachable!() } } } #[no_mangle] pub unsafe extern "C" fn __wbindgen_free(ptr: *mut u8, size: usize, align: usize) { // This happens for zero-length slices, and in that case `ptr` is // likely bogus so don't actually send this to the system allocator if size == 0 { return; } let layout = Layout::from_size_align_unchecked(size, align); dealloc(ptr, layout); } /// This is a curious function necessary to get wasm-bindgen working today, /// and it's a bit of an unfortunate hack. /// /// The general problem is that somehow we need the above two symbols to /// exist in the final output binary (__wbindgen_malloc and /// __wbindgen_free). These symbols may be called by JS for various /// bindings, so we for sure need to make sure they're exported. /// /// The problem arises, though, when what if no Rust code uses the symbols? /// For all intents and purposes it looks to LLVM and the linker like the /// above two symbols are dead code, so they're completely discarded! /// /// Specifically what happens is this: /// /// * The above two symbols are generated into some object file inside of /// libwasm_bindgen.rlib /// * The linker, LLD, will not load this object file unless *some* symbol /// is loaded from the object. In this case, if the Rust code never calls /// __wbindgen_malloc or __wbindgen_free then the symbols never get linked /// in. /// * Later when `wasm-bindgen` attempts to use the symbols they don't /// exist, causing an error. /// /// This function is a weird hack for this problem. We inject a call to this /// function in all generated code. Usage of this function should then /// ensure that the above two intrinsics are translated. /// /// Due to how rustc creates object files this function (and anything inside /// it) will be placed into the same object file as the two intrinsics /// above. That means if this function is called and referenced we'll pull /// in the object file and link the intrinsics. /// /// Ideas for how to improve this are most welcome! #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] pub fn link_mem_intrinsics() { crate::link::link_intrinsics(); } #[cfg(feature = "std")] std::thread_local! { static GLOBAL_EXNDATA: Cell<[u32; 2]> = Cell::new([0; 2]); } #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] static mut GLOBAL_EXNDATA: [u32; 2] = [0; 2]; #[cfg(all(not(feature = "std"), target_feature = "atomics"))] #[thread_local] static GLOBAL_EXNDATA: Cell<[u32; 2]> = Cell::new([0; 2]); struct GlobalExndata; impl GlobalExndata { #[cfg(feature = "std")] fn get() -> [u32; 2] { GLOBAL_EXNDATA.with(Cell::get) } #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] fn get() -> [u32; 2] { unsafe { GLOBAL_EXNDATA } } #[cfg(all(not(feature = "std"), target_feature = "atomics"))] fn get() -> [u32; 2] { GLOBAL_EXNDATA.get() } #[cfg(feature = "std")] fn set(data: [u32; 2]) { GLOBAL_EXNDATA.with(|d| d.set(data)) } #[cfg(all(not(feature = "std"), not(target_feature = "atomics")))] fn set(data: [u32; 2]) { unsafe { GLOBAL_EXNDATA = data }; } #[cfg(all(not(feature = "std"), target_feature = "atomics"))] fn set(data: [u32; 2]) { GLOBAL_EXNDATA.set(data); } } #[no_mangle] pub unsafe extern "C" fn __wbindgen_exn_store(idx: u32) { debug_assert_eq!(GlobalExndata::get()[0], 0); GlobalExndata::set([1, idx]); } pub fn take_last_exception() -> Result<(), super::JsValue> { let ret = if GlobalExndata::get()[0] == 1 { Err(super::JsValue::_new(GlobalExndata::get()[1])) } else { Ok(()) }; GlobalExndata::set([0, 0]); ret } /// An internal helper trait for usage in `#[wasm_bindgen]` on `async` /// functions to convert the return value of the function to /// `Result` which is what we'll return to JS (where an /// error is a failed future). pub trait IntoJsResult { fn into_js_result(self) -> Result; } impl IntoJsResult for () { fn into_js_result(self) -> Result { Ok(JsValue::undefined()) } } impl> IntoJsResult for T { fn into_js_result(self) -> Result { Ok(self.into()) } } impl, E: Into> IntoJsResult for Result { fn into_js_result(self) -> Result { match self { Ok(e) => Ok(e.into()), Err(e) => Err(e.into()), } } } impl> IntoJsResult for Result<(), E> { fn into_js_result(self) -> Result { match self { Ok(()) => Ok(JsValue::undefined()), Err(e) => Err(e.into()), } } } /// An internal helper trait for usage in `#[wasm_bindgen(start)]` /// functions to throw the error (if it is `Err`). pub trait Start { fn start(self); } impl Start for () { #[inline] fn start(self) {} } impl> Start for Result<(), E> { #[inline] fn start(self) { if let Err(e) = self { crate::throw_val(e.into()); } } } /// An internal helper struct for usage in `#[wasm_bindgen(main)]` /// functions to throw the error (if it is `Err`). pub struct MainWrapper(pub Option); pub trait Main { fn __wasm_bindgen_main(&mut self); } impl Main for &mut &mut MainWrapper<()> { #[inline] fn __wasm_bindgen_main(&mut self) {} } impl Main for &mut &mut MainWrapper { #[inline] fn __wasm_bindgen_main(&mut self) {} } impl> Main for &mut &mut MainWrapper> { #[inline] fn __wasm_bindgen_main(&mut self) { if let Err(e) = self.0.take().unwrap() { crate::throw_val(e.into()); } } } impl Main for &mut MainWrapper> { #[inline] fn __wasm_bindgen_main(&mut self) { if let Err(e) = self.0.take().unwrap() { crate::throw_str(&alloc::format!("{:?}", e)); } } } pub const fn flat_len(slices: [&[T]; SIZE]) -> usize { let mut len = 0; let mut i = 0; while i < slices.len() { len += slices[i].len(); i += 1; } len } pub const fn flat_byte_slices( slices: [&[u8]; SIZE], ) -> [u8; RESULT_LEN] { let mut result = [0; RESULT_LEN]; let mut slice_index = 0; let mut result_offset = 0; while slice_index < slices.len() { let mut i = 0; let slice = slices[slice_index]; while i < slice.len() { result[result_offset] = slice[i]; i += 1; result_offset += 1; } slice_index += 1; } result } // NOTE: This method is used to encode u32 into a variable-length-integer during the compile-time . // Generally speaking, the length of the encoded variable-length-integer depends on the size of the integer // but the maximum capacity can be used here to simplify the amount of code during the compile-time . pub const fn encode_u32_to_fixed_len_bytes(value: u32) -> [u8; 5] { let mut result: [u8; 5] = [0; 5]; let mut i = 0; while i < 4 { result[i] = ((value >> (7 * i)) | 0x80) as u8; i += 1; } result[4] = (value >> (7 * 4)) as u8; result } /// Trait for element types to implement `Into` for vectors of /// themselves, which isn't possible directly thanks to the orphan rule. pub trait VectorIntoJsValue: Sized { fn vector_into_jsvalue(vector: Box<[Self]>) -> JsValue; } impl From> for JsValue { fn from(vector: Box<[T]>) -> Self { T::vector_into_jsvalue(vector) } } pub fn js_value_vector_into_jsvalue>(vector: Box<[T]>) -> JsValue { let result = unsafe { JsValue::_new(super::__wbindgen_array_new()) }; for value in vector.into_vec() { let js: JsValue = value.into(); unsafe { super::__wbindgen_array_push(result.idx, js.idx) } // `__wbindgen_array_push` takes ownership over `js` and has already dropped it, // so don't drop it again. mem::forget(js); } result } } /// A wrapper type around slices and vectors for binding the `Uint8ClampedArray` /// array in JS. /// /// If you need to invoke a JS API which must take `Uint8ClampedArray` array, /// then you can define it as taking one of these types: /// /// * `Clamped<&[u8]>` /// * `Clamped<&mut [u8]>` /// * `Clamped>` /// /// All of these types will show up as `Uint8ClampedArray` in JS and will have /// different forms of ownership in Rust. #[derive(Copy, Clone, PartialEq, Debug, Eq)] pub struct Clamped(pub T); impl Deref for Clamped { type Target = T; fn deref(&self) -> &T { &self.0 } } impl DerefMut for Clamped { fn deref_mut(&mut self) -> &mut T { &mut self.0 } } /// Convenience type for use on exported `fn() -> Result` functions, where you wish to /// throw a JavaScript `Error` object. /// /// You can get wasm_bindgen to throw basic errors by simply returning /// `Err(JsError::new("message"))` from such a function. /// /// For more complex error handling, `JsError` implements `From where T: std::error::Error` by /// converting it to a string, so you can use it with `?`. Many Rust error types already do this, /// and you can use [`thiserror`](https://crates.io/crates/thiserror) to derive Display /// implementations easily or use any number of boxed error types that implement it already. /// /// /// To allow JavaScript code to catch only your errors, you may wish to add a subclass of `Error` /// in a JS module, and then implement `Into` directly on a type and instantiate that /// subclass. In that case, you would not need `JsError` at all. /// /// ### Basic example /// /// ```rust,no_run /// use wasm_bindgen::prelude::*; /// /// #[wasm_bindgen] /// pub fn throwing_function() -> Result<(), JsError> { /// Err(JsError::new("message")) /// } /// ``` /// /// ### Complex Example /// /// ```rust,no_run /// use wasm_bindgen::prelude::*; /// /// #[derive(Debug, Clone)] /// enum MyErrorType { /// SomeError, /// } /// /// use core::fmt; /// impl std::error::Error for MyErrorType {} /// impl fmt::Display for MyErrorType { /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { /// write!(f, "display implementation becomes the error message") /// } /// } /// /// fn internal_api() -> Result<(), MyErrorType> { /// Err(MyErrorType::SomeError) /// } /// /// #[wasm_bindgen] /// pub fn throwing_function() -> Result<(), JsError> { /// internal_api()?; /// Ok(()) /// } /// /// ``` #[derive(Clone, Debug)] pub struct JsError { value: JsValue, } impl JsError { /// Construct a JavaScript `Error` object with a string message #[inline] pub fn new(s: &str) -> JsError { Self { value: unsafe { JsValue::_new(crate::__wbindgen_error_new(s.as_ptr(), s.len())) }, } } } if_std! { impl From for JsError where E: std::error::Error, { fn from(error: E) -> Self { JsError::new(&error.to_string()) } } } impl From for JsValue { fn from(error: JsError) -> Self { error.value } } macro_rules! typed_arrays { ($($ty:ident $ctor:ident $clamped_ctor:ident,)*) => { $( impl From> for JsValue { fn from(mut vector: Box<[$ty]>) -> Self { let result = unsafe { JsValue::_new($ctor(vector.as_mut_ptr(), vector.len())) }; mem::forget(vector); result } } impl From>> for JsValue { fn from(mut vector: Clamped>) -> Self { let result = unsafe { JsValue::_new($clamped_ctor(vector.as_mut_ptr(), vector.len())) }; mem::forget(vector); result } } )* }; } typed_arrays! { u8 __wbindgen_uint8_array_new __wbindgen_uint8_clamped_array_new, u16 __wbindgen_uint16_array_new __wbindgen_uint16_array_new, u32 __wbindgen_uint32_array_new __wbindgen_uint32_array_new, u64 __wbindgen_biguint64_array_new __wbindgen_biguint64_array_new, i8 __wbindgen_int8_array_new __wbindgen_int8_array_new, i16 __wbindgen_int16_array_new __wbindgen_int16_array_new, i32 __wbindgen_int32_array_new __wbindgen_int32_array_new, i64 __wbindgen_bigint64_array_new __wbindgen_bigint64_array_new, f32 __wbindgen_float32_array_new __wbindgen_float32_array_new, f64 __wbindgen_float64_array_new __wbindgen_float64_array_new, } impl __rt::VectorIntoJsValue for JsValue { fn vector_into_jsvalue(vector: Box<[JsValue]>) -> JsValue { __rt::js_value_vector_into_jsvalue::(vector) } } impl __rt::VectorIntoJsValue for T { fn vector_into_jsvalue(vector: Box<[T]>) -> JsValue { __rt::js_value_vector_into_jsvalue::(vector) } } impl __rt::VectorIntoJsValue for String { fn vector_into_jsvalue(vector: Box<[String]>) -> JsValue { __rt::js_value_vector_into_jsvalue::(vector) } } impl From> for JsValue where JsValue: From>, { fn from(vector: Vec) -> Self { JsValue::from(vector.into_boxed_slice()) } } impl From>> for JsValue where JsValue: From>>, { fn from(vector: Clamped>) -> Self { JsValue::from(Clamped(vector.0.into_boxed_slice())) } } wasm-bindgen-0.2.99/src/link.rs000064400000000000000000000002521046102023000143710ustar 00000000000000// see comment in module above this in `link_mem_intrinsics` #[inline(never)] #[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))] pub fn link_intrinsics() {}