chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1 @@
{"files":{".cargo_vcs_info.json":"7bf1cd5ffa8b25f072ec88cbc426984ce9af0ebe5f00b5aeb0c6b64371efc5c2","Cargo.lock":"28e96501d2e6b8d34499858524da3be3e368b89d8e91bc66caf14bdc144358a0","Cargo.toml":"1726a65b21f19c1de1e29cd99acc89bb098ebca96ee594a5df99b24fffd185be","Cargo.toml.orig":"cb17181e34ad50944f9dbe97c4b973039a65ff83cc4c0b8b6eda959c12b2920e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"2e2fb2f199aa387373aaa0119ccd7553ae7b24d80eb479836162e0ed3535682d","build.rs":"ed13da46ab3462ed9e02a64efffefe5880ee5c38392d6b613ba72c72f54d0ada","src/cache/intern.rs":"b354990c27d418b201a918782f1aa736c2cafd31fcde694bb19aa58c5bc47449","src/cache/mod.rs":"8989143b55160dbc142cb20c6e066cf0a3f70d6c97fbc9aa0fac59bd62bd865b","src/cast.rs":"156a9b71bf9af03c5c378a1939032dfc628edbefce4aa8c37fb14948abf7a9f4","src/closure.rs":"17095f56c36e140edce091dde5f2d588a2978c0f647552e4b1635fbc0690a722","src/convert/closures.rs":"affd61989621eda81e87e2135cbdbd17870460bedb9f07c0d3e682fb12837fd1","src/convert/impls.rs":"bf561307a27a970ee36572f0168dff4745a4b892c802abd4e7e950a40a755261","src/convert/mod.rs":"83abe862e77f8d5c92102fd1df4de0854193a1b5530ad1e15b439031d7897396","src/convert/slices.rs":"d333cd1fb726e69c09b8bbcfd20745afe6b53148fc406f47f1235ee5ddf079f0","src/convert/traits.rs":"2d782495fff52c722d788927a6948d70760c06d16b169d124c90ef28f05ad3c0","src/describe.rs":"efb32293c9ec4df2b43ca2cbaf3a34d546c4af4479d07b37371f859c06c0e5e2","src/externref.rs":"0ac3f2303074e08558bc116d12a714ccf1b7b42be48efd1b8b8374e5d25ed73c","src/lib.rs":"0dc7e33c5e202898f2a64129a590c74ec9e4062874f69277d1daac48879b7bb4","src/link.rs":"96fdb40e29ffae7b9621d78eec24437bdc6db2473f6d2f8eff1f987d2b566852","src/rt/marker.rs":"8054b0b009c480dcfb42e8649f67d8c9109540210349215e393688e28bed4a4f","src/rt/mod.rs":"548beb9f2b3472cc9655c5b55bf45d41eac70b94afb6068f5c25b9058df0191b","src/sys.rs":"0bb0f5862bb40fb85789d4bca7f43b5b5e862b286ba1d4ea13bba1a4f0b48860"},"package":"6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e"}

View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "22cfd556870fa897d0b2db4c84603c1a9643298c"
},
"path_in_vcs": ""
}

175
vendor/wasm-bindgen/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,175 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bumpalo"
version = "3.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]]
name = "memchr"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "once_cell"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "proc-macro2"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "syn"
version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "wasm-bindgen"
version = "0.2.114"
dependencies = [
"cfg-if",
"once_cell",
"paste",
"rustversion",
"serde",
"serde_derive",
"serde_json",
"wasm-bindgen-macro",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16"
dependencies = [
"unicode-ident",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"

114
vendor/wasm-bindgen/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,114 @@
# 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.71"
name = "wasm-bindgen"
version = "0.2.114"
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://wasm-bindgen.github.io/wasm-bindgen"
documentation = "https://docs.rs/wasm-bindgen"
readme = "README.md"
categories = ["wasm"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/wasm-bindgen/wasm-bindgen"
[package.metadata.docs.rs]
features = ["serde-serialize"]
[features]
default = ["std"]
enable-interning = ["std"]
gg-alloc = []
msrv = []
rustversion = []
serde-serialize = [
"serde",
"serde_json",
"std",
]
spans = []
std = []
strict-macro = ["wasm-bindgen-macro/strict-macro"]
xxx_debug_only_print_generated_code = []
[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.114"
[dependencies.wasm-bindgen-shared]
version = "=0.2.114"
[dev-dependencies.once_cell]
version = "1"
[build-dependencies.rustversion-compat]
version = "1.0.6"
package = "rustversion"
[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"
uninlined_format_args = "warn"
[lints.rust]
unused_lifetimes = "warn"
[lints.rust.unexpected_cfgs]
level = "warn"
priority = 0
check-cfg = [
"cfg(wasm_bindgen_unstable_test_coverage)",
"cfg(xxx_debug_only_print_generated_code)",
]

201
vendor/wasm-bindgen/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

25
vendor/wasm-bindgen/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (c) 2014 Alex Crichton
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

142
vendor/wasm-bindgen/README.md vendored Normal file
View File

@@ -0,0 +1,142 @@
<div align="center">
<h1><code>wasm-bindgen</code></h1>
<p>
<strong>Facilitating high-level interactions between Wasm modules and JavaScript.</strong>
</p>
<p>
<a href="https://github.com/wasm-bindgen/wasm-bindgen/actions/workflows/main.yml?query=branch%3Amain"><img src="https://github.com/wasm-bindgen/wasm-bindgen/actions/workflows/main.yml/badge.svg?branch=main" alt="Build Status" /></a>
<a href="https://crates.io/crates/wasm-bindgen"><img src="https://img.shields.io/crates/v/wasm-bindgen.svg?style=flat-square" alt="Crates.io version" /></a>
<a href="https://crates.io/crates/wasm-bindgen"><img src="https://img.shields.io/crates/d/wasm-bindgen.svg?style=flat-square" alt="Download" /></a>
<a href="https://docs.rs/wasm-bindgen"><img src="https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square" alt="docs.rs docs" /></a>
</p>
<h3>
<a href="https://wasm-bindgen.github.io/wasm-bindgen/">Guide (main branch)</a>
<span> | </span>
<a href="https://docs.rs/wasm-bindgen">API Docs</a>
<span> | </span>
<a href="https://github.com/wasm-bindgen/wasm-bindgen/blob/master/CONTRIBUTING.md">Contributing</a>
<span> | </span>
<a href="https://discord.gg/xMZ7CCY">Chat</a>
</h3>
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
</div>
## 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/wasm-bindgen/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://wasm-bindgen.github.io/wasm-bindgen/)
## 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.71.
* CLI tools and their corresponding support libraries have a MSRV of v1.82.
The project aims to maintain a 2-year MSRV policy for libraries (meaning we support Rust versions released within the last 2 years), but with a shorter MSRV policy for the CLI. Changes to the MSRV may be made in patch versions, and will be logged in the CHANGELOG and MSRV history below.
### MSRV History
| Version | Library MSRV | CLI MSRV | Date |
|---------|--------------|----------|------------|
| 0.2.106 | 1.71 | 1.82 | 2025-11-xx |
| 0.2.103 | 1.57 | 1.82 | 2025-09-17 |
| 0.2.93 | 1.57 | 1.76 | 2024-08-13 |
## 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://wasm-bindgen.github.io/wasm-bindgen/contributing/index.html

43
vendor/wasm-bindgen/build.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
// Required so that `[package] links = ...` works in `Cargo.toml`.
use rustversion_compat as rustversion;
use std::env;
macro_rules! deprecated_crate_feature {
($name:literal) => {
#[cfg(feature = $name)]
{
println!("cargo:warning=The `{}` feature is deprecated and will be removed in the next major version.", $name);
}
};
}
fn main() {
println!("cargo:rerun-if-changed=build.rs");
deprecated_crate_feature!("msrv");
deprecated_crate_feature!("rustversion");
deprecated_crate_feature!("xxx_debug_only_print_generated_code");
println!("cargo:rustc-check-cfg=cfg(wbg_diagnostic)");
if rustversion::cfg!(since(1.78)) {
println!("cargo:rustc-cfg=wbg_diagnostic");
}
let target_arch = env::var_os("CARGO_CFG_TARGET_ARCH").unwrap();
let target_os = env::var_os("CARGO_CFG_TARGET_OS").unwrap();
let target_features = env::var("CARGO_CFG_TARGET_FEATURE").unwrap_or_default();
let target_features: Vec<_> = target_features.split(',').map(str::trim).collect();
println!("cargo:rustc-check-cfg=cfg(wbg_reference_types)");
if target_features.contains(&"reference-types")
|| (target_arch == "wasm32"
&& target_os == "unknown"
&& rustversion::cfg!(all(since(1.82), before(1.84))))
{
println!("cargo:rustc-cfg=wbg_reference_types");
}
}

103
vendor/wasm-bindgen/src/cache/intern.rs vendored Normal file
View File

@@ -0,0 +1,103 @@
use 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<HashMap<String, JsValue>>,
}
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<u32> {
CACHE.with(|cache| {
let cache = cache.entries.borrow();
cache.get(s).map(|x| x.idx)
})
}
fn intern_str(key: &str) {
CACHE.with(|cache| {
let entries = &cache.entries;
// Can't use `entry` because `entry` requires a `String`
if !entries.borrow().contains_key(key) {
// Note: we must not hold the borrow while we create the `JsValue`,
// because it will try to look up the value in the cache first.
let value = JsValue::from(key);
entries.borrow_mut().insert(key.to_owned(), value);
}
})
}
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);
}

1
vendor/wasm-bindgen/src/cache/mod.rs vendored Normal file
View File

@@ -0,0 +1 @@
pub mod intern;

172
vendor/wasm-bindgen/src/cast.rs vendored Normal file
View File

@@ -0,0 +1,172 @@
use crate::{convert::TryFromJsValue, JsValue};
/// A trait for dynamic checked and unchecked casting between JS types.
///
/// Unlike [`crate::Upcast`], which provides type-safe zero-cost type
/// conversions for generic type wrappers, this trait can be used to
/// perform arbitrary casts with JS instance checking.
///
/// 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<JsValue> + Into<JsValue>,
{
/// 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<T>(&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::<T>()`
/// returns `false`, and otherwise it will return `Ok(T)` manufactured with
/// an unchecked cast (verified correct via the `has_type` operation).
fn dyn_into<T>(self) -> Result<T, Self>
where
T: JsCast,
{
if self.has_type::<T>() {
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::<T>()`
/// returns `false`, and otherwise it will return `Some(&T)` manufactured
/// with an unchecked cast (verified correct via the `has_type` operation).
fn dyn_ref<T>(&self) -> Option<&T>
where
T: JsCast,
{
if self.has_type::<T>() {
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<T>(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<T>(&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<T>(&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;
}
impl<T: JsCast> TryFromJsValue for T {
#[inline]
fn try_from_js_value(val: JsValue) -> Result<Self, JsValue> {
val.dyn_into()
}
#[inline]
fn try_from_js_value_ref(val: &JsValue) -> Option<Self> {
val.clone().dyn_into().ok()
}
}

978
vendor/wasm-bindgen/src/closure.rs vendored Normal file
View File

@@ -0,0 +1,978 @@
//! Support for closures in `wasm-bindgen`
//!
//! This module defines the [`ScopedClosure`] type which is used to pass Rust closures
//! to JavaScript. All closures are unwind safe by default: panics are caught and converted to
//! JavaScript exceptions when built with `panic=unwind`.
//!
//! # Immutable by Default
//!
//! The closure API defaults to **immutable** (`Fn`) closures because they are more
//! likely to satisfy `UnwindSafe` automatically:
//!
//! - `&T` where `T: RefUnwindSafe` is `UnwindSafe`
//! - `&mut T` is **never** `UnwindSafe` regardless of `T`
//!
//! This means:
//! - [`ScopedClosure::borrow`] creates an immutable `Fn` closure
//! - [`ScopedClosure::borrow_mut`] creates a mutable `FnMut` closure
//!
//! Immutable closures can be upcasted to mutable closures using [`upcast_ref`](crate::Upcast::upcast_ref).
//!
//! # Type Aliases
//!
//! - [`ScopedClosure<'a, T>`] — The unified closure type with a lifetime parameter
//! - [`Closure<T>`] — Alias for `ScopedClosure<'static, T>` (for backwards compatibility)
//!
//! # Unwind Safety
//!
//! For immediate/synchronous callbacks, use `&dyn FnMut` / `&dyn Fn`, when you are
//! **absolutely sure** the code will support unwind safety.
//!
//! For [`ScopedClosure`], the default constructors (`borrow`, `borrow_mut`, `own`) catch
//! panics, while the `_aborting` variants (`borrow_aborting`, `borrow_mut_aborting`, etc.) do not.
//!
//! # Ownership Model
//!
//! `ScopedClosure` follows the same ownership model as other wasm-bindgen types:
//! the JavaScript reference remains valid until the Rust value is dropped. When
//! dropped, the closure is invalidated and any subsequent calls from JavaScript
//! will throw an exception.
//!
//! For borrowed closures created with `borrow`/`borrow_mut`, Rust's borrow checker
//! ensures the `ScopedClosure` cannot outlive the closure's captured data.
//!
//! See the [`ScopedClosure`] type documentation for detailed examples.
#![allow(clippy::fn_to_numeric_cast)]
use alloc::boxed::Box;
use alloc::string::String;
use core::fmt;
use core::mem::{self, ManuallyDrop};
use crate::__rt::marker::ErasableGeneric;
use crate::__rt::marker::MaybeUnwindSafe;
use crate::describe::*;
use crate::JsValue;
use crate::{convert::*, JsCast};
use core::marker::PhantomData;
use core::panic::AssertUnwindSafe;
#[wasm_bindgen_macro::wasm_bindgen(wasm_bindgen = crate)]
extern "C" {
type JsClosure;
#[wasm_bindgen(method)]
fn _wbg_cb_unref(js: &JsClosure);
}
/// A closure with a lifetime parameter that represents a Rust closure passed to JavaScript.
///
/// `ScopedClosure<'a, T>` is the unified closure type. The lifetime `'a` indicates
/// how long the closure is valid:
///
/// - **`ScopedClosure<'static, T>`** - An owned closure with heap-allocated data. Requires
/// `'static` captures. Use for long-lived closures like event listeners and timers.
/// Created with [`Closure::new`] or [`ScopedClosure::own`]. May transfer ownership to the
/// JS GC using finalizers.
///
/// - **`ScopedClosure<'a, T>`** (non-`'static`) - A borrowed closure referencing stack data.
/// Allows non-`'static` captures. Use for immediate/synchronous callbacks. Created with
/// [`ScopedClosure::borrow`] (for `FnMut`) or [`ScopedClosure::borrow_immutable`] (for `Fn`).
/// Cannot transfer ownership to JS GC.
///
/// [`Closure<T>`] is currently a type alias for `ScopedClosure<'static, T>`. In
/// a future release, a lifetime argument will be added to this alias.
///
/// # Ownership Model
///
/// `ScopedClosure` follows the same ownership model as other wasm-bindgen types:
/// the JavaScript reference remains valid until the Rust value is dropped. When
/// dropped, the closure is invalidated and any subsequent calls from JavaScript
/// will throw: "closure invoked recursively or after being dropped".
///
/// For `'static` closures, you can also:
/// - Pass by value to transfer ownership to JS (implements [`IntoWasmAbi`])
/// - Call [`forget()`](Self::forget) to leak the closure (JS can use it indefinitely)
/// - Call [`into_js_value()`](Self::into_js_value) to transfer to JS GC management
///
/// # Lifetime Safety
///
/// For borrowed closures, Rust's borrow checker ensures that `ScopedClosure` cannot
/// be held longer than the closure's captured data:
///
/// ```ignore
/// let mut sum = 0;
/// let mut f = |x: u32| { sum += x; }; // f borrows sum
/// let closure = ScopedClosure::borrow(&mut f); // closure borrows f
/// // closure cannot outlive f, and f cannot outlive sum
/// ```
///
/// # Examples
///
/// ## Borrowed closures with `ScopedClosure::borrow`
///
/// Use for immediate/synchronous callbacks where JS calls the closure right away:
///
/// ```ignore
/// use wasm_bindgen::prelude::*;
///
/// #[wasm_bindgen]
/// extern "C" {
/// fn call_immediately(cb: &ScopedClosure<dyn FnMut(u32)>);
/// }
///
/// let mut sum = 0;
/// {
/// let mut f = |x: u32| { sum += x; };
/// let closure = ScopedClosure::borrow(&mut f);
/// call_immediately(&closure);
/// } // closure dropped here, JS function invalidated
/// assert_eq!(sum, 42);
/// ```
///
/// ## Owned closures with `Closure::new`
///
/// Use for long-lived callbacks like event listeners and timers:
///
/// ```ignore
/// use wasm_bindgen::prelude::*;
///
/// #[wasm_bindgen]
/// extern "C" {
/// fn setInterval(closure: &Closure<dyn FnMut()>, time: u32) -> i32;
/// }
///
/// // Closure::new requires 'static, so use `move` to capture by value
/// let cb = Closure::new(move || {
/// // ...
/// });
/// setInterval(&cb, 1000);
/// // Must keep `cb` alive or call `cb.forget()` to transfer to JS
/// ```
///
/// ## Transferring ownership to JS
///
/// Pass a `ScopedClosure<'static, T>` by value to transfer ownership:
///
/// ```ignore
/// use wasm_bindgen::prelude::*;
///
/// #[wasm_bindgen]
/// extern "C" {
/// fn set_one_shot_callback(cb: ScopedClosure<dyn FnMut()>);
/// }
///
/// let cb = ScopedClosure::own(|| { /* ... */ });
/// set_one_shot_callback(cb); // Ownership transferred, no need to store
/// ```
pub struct ScopedClosure<'a, T: ?Sized> {
js: JsClosure,
// careful: must be Box<T> not just T because unsized PhantomData
// seems to have weird interaction with Pin<>
_marker: PhantomData<Box<T>>,
_lifetime: PhantomData<&'a ()>,
}
/// Alias for [`ScopedClosure<'static, T>`] for backwards compatibility.
///
/// In a future major version, `Closure` will become `ScopedClosure<'a, T>` with a
/// lifetime parameter.
pub type Closure<T> = ScopedClosure<'static, T>;
// ScopedClosure is Unpin because it only contains a JsValue (which is just a u32)
// and PhantomData markers. The closure data is either on the heap (owned) or
// referenced through a raw pointer (borrowed), neither of which is stored inline.
impl<T: ?Sized> Unpin for ScopedClosure<'_, T> {}
fn _assert_compiles<T>(pin: core::pin::Pin<&mut ScopedClosure<'static, T>>) {
let _ = &mut *pin.get_mut();
}
impl<T: ?Sized> Drop for ScopedClosure<'_, T> {
fn drop(&mut self) {
// Invalidate the closure on the JS side.
//
// The JS bindings distinguish owned vs borrowed closures via the `dtor_idx`
// encoded in `WasmDescribe`: owned closures pass a non-zero destructor
// function pointer, borrowed closures pass `0`.
//
// For owned closures (`Closure::new`/`ScopedClosure::own`), this decreases
// the refcount and frees the Rust heap data when the count reaches zero.
//
// For borrowed closures (`ScopedClosure::borrow`/`borrow_mut`), this sets
// state.a = state.b = 0 to prevent any further calls to the closure.
self.js._wbg_cb_unref();
}
}
impl<'a, T> ScopedClosure<'a, T>
where
T: ?Sized + WasmClosure,
{
/// Obtain a `&JsValue` reference for this closure
pub fn as_js_value(&self) -> &JsValue {
self.js.unchecked_ref()
}
}
/// Methods for creating and managing `'static` closures.
///
/// These methods are only available on `ScopedClosure<'static, T>`
/// not on borrowed `ScopedClosure<'a, T>` where `'a` is not `'static`.
impl<T> ScopedClosure<'static, T>
where
T: ?Sized + WasmClosure,
{
/// Alias for [`Closure::own`].
///
/// Creates a new static owned `ScopedClosure<'static, T>` from the provided
/// Rust function, with panic unwind support.
///
/// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
///
/// Supports unwind via its UnwindSafe bound when building with panic=unwind.
/// Alternatively, pass `Closure::own(AssertUnwindSafe(...))` to assert unwind
/// safety, or use [`own_assert_unwind_safe`](Self::own_assert_unwind_safe) or
/// [`own_aborting`](Self::own_aborting).
///
/// When provided to a JS function as an own value, to be managed by the JS GC.
///
/// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
/// an associated lifetime (defaults to immutable `Fn`).
pub fn new<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
{
Self::own(t)
}
/// Creates a new static owned `ScopedClosure<'static, T>` from the provided
/// Rust function, with panic unwind support.
///
/// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
///
/// Supports unwind via its UnwindSafe bound when building with panic=unwind.
/// Alternatively, pass `Closure::own(AssertUnwindSafe(...))` to assert unwind
/// safety, or use [`own_assert_unwind_safe`](Self::own_assert_unwind_safe) or
/// [`own_aborting`](Self::own_aborting).
///
/// When provided to a JS function as an own value, to be managed by the JS GC.
///
/// See [`borrow`](Self::borrow) for creating a borrowed `ScopedClosure` with
/// an associated lifetime (defaults to immutable `Fn`).
pub fn own<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + MaybeUnwindSafe + 'static,
{
Self::wrap_maybe_aborting::<true>(Box::new(t))
}
/// Creates a new owned `'static` closure that aborts on panic.
///
/// Unlike [`own`](Self::own), this version does NOT catch panics and does NOT
/// require `UnwindSafe`. If the closure panics, the process will abort.
///
/// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
///
/// When provided to a JS function as an own value, to be managed by the JS GC.
///
/// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
/// `ScopedClosure` with an associated lifetime.
///
/// **Note: Not unwind safe. Prefer [`own`](Self::own) or `own` with
/// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
pub fn own_aborting<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + 'static,
{
Self::wrap_maybe_aborting::<false>(Box::new(t))
}
/// Creates a new static owned `ScopedClosure<'static, T>` from the provided
/// Rust function, with panic unwind support.
///
/// The type parameter `T` determines whether the closure is `Fn` or `FnMut`.
///
/// When provided to a JS function as an own value, to be managed by the JS GC.
///
/// **Safety: Unwind safety is assumed when using this function, like using
/// `AssertUnwindSafe(...)`, this must be verified explicitly.**
///
/// See [`borrow_aborting`](Self::borrow_aborting) for creating a borrowed
/// `ScopedClosure` with an associated lifetime.
pub fn own_assert_unwind_safe<F>(t: F) -> Self
where
F: IntoWasmClosure<T> + 'static,
{
Self::wrap_maybe_aborting::<true>(Box::new(t))
}
/// A more direct version of `Closure::new` which creates a `Closure` from
/// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
///
/// Supports unwind via its UnwindSafe bound when building with panic=unwind.
/// Alternatively, use [`wrap_assert_unwind_safe`](Self::wrap_assert_unwind_safe)
/// to assert unwind safety, or use [`wrap_aborting`](Self::wrap_aborting).
///
pub fn wrap<F>(data: Box<F>) -> Self
where
F: IntoWasmClosure<T> + ?Sized + MaybeUnwindSafe,
{
Self::wrap_maybe_aborting::<true>(data)
}
/// A more direct version of `Closure::new` which creates a `Closure` from
/// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
///
/// This version aborts on panics.
pub fn wrap_aborting<F>(data: Box<F>) -> Self
where
F: IntoWasmClosure<T> + ?Sized,
{
Self::wrap_maybe_aborting::<false>(data)
}
/// A more direct version of `Closure::new` which creates a `Closure` from
/// a `Box<dyn Fn>`/`Box<dyn FnMut>`, which is how it's kept internally.
///
/// **Safety: Unwind safety is assumed when using this function, like using
/// `AssertUnwindSafe(...)`, this must be verified explicitly.**
///
/// This version catches panics when unwinding is available.
pub fn wrap_assert_unwind_safe<F>(data: Box<F>) -> Self
where
F: IntoWasmClosure<T> + ?Sized,
{
Self::wrap_maybe_aborting::<true>(data)
}
fn wrap_maybe_aborting<const UNWIND_SAFE: bool>(
data: Box<impl IntoWasmClosure<T> + ?Sized>,
) -> Self {
Self {
js: crate::__rt::wbg_cast(OwnedClosure::<T, UNWIND_SAFE>(data.unsize())),
_marker: PhantomData,
_lifetime: PhantomData,
}
}
/// Creates a scoped closure by borrowing an immutable `Fn` closure with
/// panic unwind support.
///
/// This is the recommended way to pass closures to JavaScript for immediate/
/// synchronous use. Unlike [`Closure::own`], this does not require the closure
/// to be `'static`, allowing you to capture references to local variables.
///
/// Use [`borrow_mut`](Self::borrow_mut) when you need to mutate captured state.
///
/// The returned `ScopedClosure<'a, _>` has lifetime `'a` from the closure
/// reference, which means it cannot outlive the closure or any data the
/// closure captures.
///
/// Supports unwind via its UnwindSafe bound when building with panic=unwind.
/// Wrap with `AssertUnwindSafe` if necessary to achieve this bound, or
/// use [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) or
/// [`borrow_aborting`](Self::borrow_aborting) for non-unwind-safe functions.
///
/// The resulting closure can be upcasted to `FnMut` using [`upcast_ref`](crate::Upcast::upcast_ref).
///
/// # When to use scoped closures
///
/// Use `ScopedClosure::borrow` or `ScopedClosure::borrow_mut` when:
/// - JavaScript will call the closure immediately and not retain it
/// - You need to capture non-`'static` references
/// - You want automatic cleanup when the `ScopedClosure` is dropped
///
/// # Closure lifetime
///
/// The JavaScript function is only valid while the `ScopedClosure` exists.
/// Once dropped, the JavaScript function is invalidated. If JavaScript retains
/// a reference and calls it later, it will throw: "closure invoked recursively
/// or after being dropped".
///
/// Rust's borrow checker ensures `ScopedClosure` cannot outlive the closure's
/// captured data, preventing use-after-free bugs.
///
/// # Example
///
/// ```ignore
/// use wasm_bindgen::prelude::*;
///
/// #[wasm_bindgen]
/// extern "C" {
/// fn call_with_value(cb: &ScopedClosure<dyn Fn(u32)>, value: u32);
/// fn call_fnmut(cb: &ScopedClosure<dyn FnMut(u32)>, value: u32);
/// }
///
/// let data = vec![1, 2, 3];
/// let f = |x| {
/// println!("data len: {}, x: {}", data.len(), x);
/// };
/// let closure = ScopedClosure::borrow(&f);
/// call_with_value(&closure, 42);
/// // Can also upcast to FnMut
/// call_fnmut(closure.upcast_ref(), 42);
/// ```
pub fn borrow<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + MaybeUnwindSafe + ?Sized,
{
Self::borrow_assert_unwind_safe(t)
}
/// Like [`borrow`](Self::borrow), but does not catch panics.
///
/// If the closure panics, the process will abort. This variant does not
/// require `UnwindSafe`.
///
/// **Note: Not unwind safe. Prefer [`borrow`](Self::borrow) or
/// [`borrow_assert_unwind_safe`](Self::borrow_assert_unwind_safe) when possible.**
pub fn borrow_aborting<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + ?Sized,
{
Self::wrap_borrow::<_, false>(t)
}
/// Like [`borrow`](Self::borrow), but catches panics without requiring `MaybeUnwindSafe`.
///
/// **Safety: Unwind safety is assumed when using this function, like using
/// `AssertUnwindSafe(...)`, this must be verified explicitly.**
pub fn borrow_assert_unwind_safe<'a, F>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + ?Sized,
{
Self::wrap_borrow::<_, true>(t)
}
fn wrap_borrow<'a, F, const UNWIND_SAFE: bool>(t: &'a F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRef<T> + ?Sized,
{
let t: &T = t.unsize_closure_ref();
let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
ScopedClosure {
js: crate::__rt::wbg_cast(BorrowedClosure::<T, UNWIND_SAFE> {
data: WasmSlice { ptr, len },
_marker: PhantomData,
}),
_marker: PhantomData,
_lifetime: PhantomData,
}
}
/// Creates a scoped closure by mutably borrowing a `FnMut` closure.
///
/// Use this for closures that need to mutate captured state. For closures that
/// don't need mutation, prefer [`borrow`](Self::borrow) which creates an immutable
/// `Fn` closure that is more likely to satisfy `UnwindSafe` automatically.
///
/// Supports unwind via its UnwindSafe bound when building with panic=unwind.
/// Wrap with `AssertUnwindSafe` if necessary to achieve this bound, or
/// use [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) or
/// [`borrow_mut_aborting`](Self::borrow_mut_aborting) for non-unwind-safe functions.
///
/// See [`borrow`](Self::borrow) for full documentation on scoped closures.
///
/// # Example
///
/// ```ignore
/// use wasm_bindgen::prelude::*;
///
/// #[wasm_bindgen]
/// extern "C" {
/// fn call_three_times(cb: &ScopedClosure<dyn FnMut(u32)>);
/// }
///
/// let mut sum = 0;
/// let closure = ScopedClosure::borrow_mut(&mut |x: u32| {
/// sum += x;
/// });
/// call_three_times(&closure);
/// // closure dropped, `sum` is accessible again
/// assert_eq!(sum, 6); // 1 + 2 + 3
/// ```
pub fn borrow_mut<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + MaybeUnwindSafe + ?Sized,
{
Self::borrow_mut_assert_unwind_safe(t)
}
/// Like [`borrow_mut`](Self::borrow_mut), but does not catch panics.
///
/// If the closure panics, the process will abort. This variant does not
/// require `UnwindSafe`.
///
/// **Note: Not unwind safe. Prefer [`borrow_mut`](Self::borrow_mut) or
/// [`borrow_mut_assert_unwind_safe`](Self::borrow_mut_assert_unwind_safe) when possible.**
pub fn borrow_mut_aborting<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + ?Sized,
{
Self::wrap_borrow_mut::<_, false>(t)
}
/// Like [`borrow_mut`](Self::borrow_mut), but catches panics without requiring `MaybeUnwindSafe`.
///
/// **Safety: Unwind safety is assumed when using this function, like using
/// `AssertUnwindSafe(...)`, this must be verified explicitly.**
pub fn borrow_mut_assert_unwind_safe<'a, F>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + ?Sized,
{
Self::wrap_borrow_mut::<_, true>(t)
}
fn wrap_borrow_mut<'a, F, const UNWIND_SAFE: bool>(t: &'a mut F) -> ScopedClosure<'a, T::Static>
where
F: IntoWasmClosureRefMut<T> + ?Sized,
{
let t: &mut T = t.unsize_closure_ref();
let (ptr, len): (u32, u32) = unsafe { mem::transmute_copy(&t) };
ScopedClosure {
js: crate::__rt::wbg_cast(BorrowedClosure::<T, UNWIND_SAFE> {
data: WasmSlice { ptr, len },
_marker: PhantomData,
}),
_marker: PhantomData,
_lifetime: PhantomData,
}
}
/// 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.
///
/// # Safety Note
///
/// This method is only available on `'static` closures. Calling it on a
/// borrowed `ScopedClosure` would be unsound because the closure data
/// would become invalid when the borrow ends.
pub fn into_js_value(self) -> JsValue {
let idx = self.js.idx;
mem::forget(self);
JsValue::_new(idx)
}
/// Same as `mem::forget(self)`.
///
/// This can be used to fully relinquish closure ownership to the JS.
///
/// # Safety Note
///
/// This method is only available on `'static` closures. Calling it on a borrowed
/// `ScopedClosure` would be unsound because the closure data would become invalid
/// when the borrow ends.
pub fn forget(self) {
mem::forget(self);
}
/// 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<dyn FnMut(A...)
/// -> 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<dyn FnMut() -> String> = Closure::once(f);
/// ```
///
/// Note: the `A` and `R` type parameters are here just for backward compat
/// and will be removed in the future.
pub fn once<F, A, R>(fn_once: F) -> Self
where
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
{
Closure::wrap_maybe_aborting::<true>(fn_once.into_fn_mut())
}
/// Create a `Closure` from a function that can only be called once.
///
/// Unlike `once`, this version does NOT catch panics and does NOT require `UnwindSafe`.
/// If the closure panics, the process will abort.
///
/// Use this when:
/// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
/// - You don't need panic catching across the JS boundary
/// - You prefer abort-on-panic behavior
///
/// Since we have no way of enforcing that JS cannot attempt to call this
/// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
/// -> R>` that will dynamically throw a JavaScript error if called more
/// than once.
///
/// **Note: Not unwind safe. Prefer [`once`](Self::once) or `once` with
/// [`AssertUnwindSafe`](core::panic::AssertUnwindSafe) when possible.**
///
/// Note: the `A` and `R` type parameters are here just for backward compat
/// and will be removed in the future.
pub fn once_aborting<F, A, R>(fn_once: F) -> Self
where
F: WasmClosureFnOnceAbort<T, A, R>,
{
Closure::wrap_maybe_aborting::<false>(fn_once.into_fn_mut())
}
/// Create a `Closure` from a function that can only be called once,
/// with panic unwind support.
///
/// **Safety: Unwind safety is assumed when using this function, like using
/// `AssertUnwindSafe(...)`, this must be verified explicitly.**
///
/// Use this when:
/// - Your closure captures types that aren't `UnwindSafe` (like `Rc<Cell<T>>`)
/// - You still want panics to be caught and converted to JS exceptions
///
/// Since we have no way of enforcing that JS cannot attempt to call this
/// `FnOnce(A...) -> R` more than once, this produces a `Closure<dyn FnMut(A...)
/// -> R>` that will dynamically throw a JavaScript error if called more
/// than once.
///
/// Note: the `A` and `R` type parameters are here just for backward compat
/// and will be removed in the future.
pub fn once_assert_unwind_safe<F, A, R>(fn_once: F) -> Self
where
F: WasmClosureFnOnceAbort<T, A, R>,
{
Closure::wrap_maybe_aborting::<true>(fn_once.into_fn_mut())
}
// TODO: Update once closures to be generated on construction as once
// closures instead of using wrap(). Then we can share the same into_js()
// function between all closures, and deprecate this method.
/// 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::<js_sys::Function>());
/// ```
///
/// Note: the `A` and `R` type parameters are here just for backward compat
/// and will be removed in the future.
pub fn once_into_js<F, A, R>(fn_once: F) -> JsValue
where
F: WasmClosureFnOnce<T, A, R> + MaybeUnwindSafe,
{
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<FnMut: ?Sized, A, R>: 'static {
fn into_fn_mut(self) -> Box<FnMut>;
fn into_js_function(self) -> JsValue;
}
/// A trait for converting an `FnOnce(A...) -> R` into a `FnMut(A...) -> R` that
/// will throw if ever called more than once. This variant does not require UnwindSafe.
#[doc(hidden)]
pub trait WasmClosureFnOnceAbort<FnMut: ?Sized, A, R>: 'static {
fn into_fn_mut(self) -> Box<FnMut>;
fn into_js_function(self) -> JsValue;
}
impl<T: ?Sized> AsRef<JsValue> for ScopedClosure<'_, T> {
fn as_ref(&self) -> &JsValue {
&self.js
}
}
/// Internal representation of an owned closure sent to JS.
/// `UNWIND_SAFE` selects the invoke shim: `true` catches panics, `false` does not.
#[repr(transparent)]
struct OwnedClosure<T: ?Sized, const UNWIND_SAFE: bool>(Box<T>);
/// Internal representation of a borrowed closure sent to JS.
/// `UNWIND_SAFE` selects the invoke shim: `true` catches panics, `false` does not.
struct BorrowedClosure<T: ?Sized, const UNWIND_SAFE: bool> {
data: WasmSlice,
_marker: PhantomData<T>,
}
unsafe extern "C" fn destroy<T: ?Sized>(a: usize, b: usize) {
if a == 0 {
return;
}
drop(mem::transmute_copy::<_, Box<T>>(&(a, b)));
}
impl<T, const UNWIND_SAFE: bool> WasmDescribe for OwnedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(CLOSURE);
inform(destroy::<T> as *const () as usize as u32);
inform(T::IS_MUT as u32);
T::describe_invoke::<UNWIND_SAFE>();
}
}
impl<T, const UNWIND_SAFE: bool> WasmDescribe for BorrowedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(CLOSURE);
inform(0);
inform(T::IS_MUT as u32);
T::describe_invoke::<UNWIND_SAFE>();
}
}
impl<T, const UNWIND_SAFE: bool> IntoWasmAbi for OwnedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
type Abi = WasmSlice;
fn into_abi(self) -> WasmSlice {
let (a, b): (usize, usize) = unsafe { mem::transmute_copy(&ManuallyDrop::new(self)) };
WasmSlice {
ptr: a as u32,
len: b as u32,
}
}
}
impl<T, const UNWIND_SAFE: bool> IntoWasmAbi for BorrowedClosure<T, UNWIND_SAFE>
where
T: WasmClosure + ?Sized,
{
type Abi = WasmSlice;
fn into_abi(self) -> WasmSlice {
self.data
}
}
impl<T> WasmDescribe for ScopedClosure<'_, T>
where
T: WasmClosure + ?Sized,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(EXTERNREF);
}
}
// `ScopedClosure` can be passed by reference to imports (for any lifetime).
impl<T> IntoWasmAbi for &ScopedClosure<'_, T>
where
T: WasmClosure + ?Sized,
{
type Abi = u32;
fn into_abi(self) -> u32 {
(&self.js).into_abi()
}
}
impl<T> OptionIntoWasmAbi for &ScopedClosure<'_, T>
where
T: WasmClosure + ?Sized,
{
fn none() -> Self::Abi {
0
}
}
/// `'static` closures can be passed by value to JS, transferring ownership.
///
/// This is useful for one-shot callbacks where you want JS to own the closure.
/// The closure will be cleaned up by JS GC (if weak references are supported)
/// or will leak (if weak references are not supported).
///
/// # Example
///
/// ```ignore
/// #[wasm_bindgen]
/// extern "C" {
/// fn set_one_shot_callback(cb: Closure<dyn FnMut()>);
/// }
///
/// let cb = Closure::new(|| { /* ... */ });
/// set_one_shot_callback(cb); // Ownership transferred to JS
/// // No need to store or forget the closure
/// ```
impl<T> IntoWasmAbi for ScopedClosure<'static, T>
where
T: WasmClosure + ?Sized,
{
type Abi = u32;
fn into_abi(self) -> u32 {
let idx = self.js.idx;
mem::forget(self);
idx
}
}
impl<T> OptionIntoWasmAbi for ScopedClosure<'static, T>
where
T: WasmClosure + ?Sized,
{
fn none() -> Self::Abi {
0
}
}
fn _check() {
fn _assert<T: IntoWasmAbi>() {}
// ScopedClosure by reference (any lifetime)
_assert::<&ScopedClosure<dyn Fn()>>();
_assert::<&ScopedClosure<dyn Fn(String)>>();
_assert::<&ScopedClosure<dyn Fn() -> String>>();
_assert::<&ScopedClosure<dyn FnMut()>>();
_assert::<&ScopedClosure<dyn FnMut(String)>>();
_assert::<&ScopedClosure<dyn FnMut() -> String>>();
// ScopedClosure by value (only 'static)
_assert::<ScopedClosure<'static, dyn Fn()>>();
_assert::<ScopedClosure<'static, dyn FnMut()>>();
_assert::<Closure<dyn Fn()>>();
_assert::<Closure<dyn FnMut()>>();
}
impl<T> fmt::Debug for ScopedClosure<'_, T>
where
T: ?Sized,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Closure {{ ... }}")
}
}
/// 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: WasmDescribe {
const IS_MUT: bool;
/// The `'static` version of `Self`. For example, if `Self` is `dyn Fn() + 'a`,
/// then `Static` is `dyn Fn()` (implicitly `'static`).
type Static: ?Sized + WasmClosure;
/// The mutable version of this closure type.
/// For `dyn Fn(...) -> R` this is `dyn FnMut(...) -> R`.
/// For `dyn FnMut(...) -> R` this is itself.
type AsMut: ?Sized;
/// Emit the FUNCTION descriptor with the invoke shim selected by
/// `UNWIND_SAFE`: `true` picks the panic-catching shim, `false`
/// picks the non-catching shim.
fn describe_invoke<const UNWIND_SAFE: bool>();
}
unsafe impl<T: WasmClosure> WasmClosure for AssertUnwindSafe<T> {
type Static = T::Static;
const IS_MUT: bool = T::IS_MUT;
type AsMut = T::AsMut;
fn describe_invoke<const UNWIND_SAFE: bool>() {
T::describe_invoke::<UNWIND_SAFE>();
}
}
/// 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<T: ?Sized> {
fn unsize(self: Box<Self>) -> Box<T>;
}
impl<T: ?Sized + WasmClosure> IntoWasmClosure<T> for T {
fn unsize(self: Box<Self>) -> Box<T> {
self
}
}
/// Trait for converting a reference to a closure into a trait object reference.
///
/// This trait is not stable and it's not recommended to use this in bounds or
/// implement yourself.
#[doc(hidden)]
pub trait IntoWasmClosureRef<T: ?Sized> {
fn unsize_closure_ref(&self) -> &T;
}
/// Trait for converting a mutable reference to a closure into a trait object reference.
///
/// This trait is not stable and it's not recommended to use this in bounds or
/// implement yourself.
#[doc(hidden)]
pub trait IntoWasmClosureRefMut<T: ?Sized> {
fn unsize_closure_ref(&mut self) -> &mut T;
}
// Blanket impl for AssertUnwindSafe - delegates to inner type
impl<T: ?Sized, F> IntoWasmClosureRef<T> for AssertUnwindSafe<F>
where
F: IntoWasmClosureRef<T>,
{
fn unsize_closure_ref(&self) -> &T {
self.0.unsize_closure_ref()
}
}
impl<T: ?Sized, F> IntoWasmClosureRefMut<T> for AssertUnwindSafe<F>
where
F: IntoWasmClosureRefMut<T>,
{
fn unsize_closure_ref(&mut self) -> &mut T {
self.0.unsize_closure_ref()
}
}
// In ScopedClosure, the Rust closure type is the phantom type that erases.
unsafe impl<T: ?Sized + WasmClosure> ErasableGeneric for ScopedClosure<'_, T> {
type Repr = ScopedClosure<'static, dyn FnMut()>;
}

View File

@@ -0,0 +1,504 @@
use alloc::boxed::Box;
use core::mem;
use core::panic::AssertUnwindSafe;
use crate::__rt::marker::ErasableGeneric;
use crate::__rt::maybe_catch_unwind;
use crate::closure::{
Closure, IntoWasmClosure, IntoWasmClosureRef, IntoWasmClosureRefMut, ScopedClosure,
WasmClosure, WasmClosureFnOnce, WasmClosureFnOnceAbort,
};
use crate::convert::slices::WasmSlice;
use crate::convert::traits::UpcastFrom;
use crate::convert::RefFromWasmAbi;
use crate::convert::{FromWasmAbi, IntoWasmAbi, ReturnWasmAbi, WasmAbi, WasmRet};
use crate::describe::{inform, WasmDescribe, FUNCTION};
use crate::sys::Undefined;
use crate::throw_str;
use crate::JsValue;
use crate::UnwrapThrowExt;
macro_rules! closures {
// Unwind safe passing
([$($maybe_unwind_safe:tt)*] $($rest:tt)*) => {
closures!(@process [$($maybe_unwind_safe)*] $($rest)*);
};
// One-arity recurse
(@process [$($unwind_safe:tt)*] ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) $($rest:tt)*) => {
closures!(@impl_for_args ($($var),*) FromWasmAbi [$($unwind_safe)*] $($var::from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
closures!(@process [$($unwind_safe)*] $($rest)*);
};
// Base case
(@process [$($unwind_safe:tt)*]) => {};
// A counter helper to count number of arguments.
(@count_one $ty:ty) => (1);
(@describe ( $($ty:ty),* )) => {
// Needs to be a constant so that interpreter doesn't crash on
// unsupported operations in debug mode.
const ARG_COUNT: u32 = 0 $(+ closures!(@count_one $ty))*;
inform(ARG_COUNT);
$(<$ty>::describe();)*
};
// This silly helper is because by default Rust infers `|var_with_ref_type| ...` closure
// as `impl Fn(&'outer_lifetime A)` instead of `impl for<'temp_lifetime> Fn(&'temp_lifetime A)`
// while `|var_with_ref_type: &A|` makes it use the higher-order generic as expected.
(@closure ($($ty:ty),*) $($var:ident)* $body:block) => (move |$($var: $ty),*| $body);
(@impl_for_fn $is_mut:literal [$($mut:ident)?] $Fn:ident $FnArgs:tt $FromWasmAbi:ident $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (const _: () = {
impl<$($var,)* R> IntoWasmAbi for &'_ $($mut)? (dyn $Fn $FnArgs -> R + '_)
where
Self: WasmDescribe,
{
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 }
}
}
}
unsafe impl<'a, $($var,)* R> ErasableGeneric for &'a $($mut)? (dyn $Fn $FnArgs -> R + 'a)
where
$($var: ErasableGeneric,)*
R: ErasableGeneric
{
type Repr = &'static (dyn $Fn ($(<$var as ErasableGeneric>::Repr,)*) -> <R as ErasableGeneric>::Repr + 'static);
}
// Invoke shim for closures. The const generic `UNWIND_SAFE` controls
// whether panics are caught and converted to JS exceptions (`true`) or
// left to unwind/abort (`false`). When `panic=unwind` is not available,
// `UNWIND_SAFE` has no effect — panics always abort.
#[allow(non_snake_case)]
unsafe extern "C-unwind" fn invoke<$($var: $FromWasmAbi,)* R: ReturnWasmAbi, const UNWIND_SAFE: bool>(
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<R::Abi> {
if a == 0 {
throw_str("closure invoked recursively or after being dropped");
}
let ret = {
let f: & $($mut)? dyn $Fn $FnArgs -> R = mem::transmute((a, b));
$(
let $var = $var::Abi::join($arg1, $arg2, $arg3, $arg4);
)*
if UNWIND_SAFE {
maybe_catch_unwind(AssertUnwindSafe(|| f($($var_expr),*)))
} else {
f($($var_expr),*)
}
};
ret.return_abi().into()
}
#[allow(clippy::fn_to_numeric_cast)]
impl<$($var,)* R> WasmDescribe for dyn $Fn $FnArgs -> R + '_
where
$($var: $FromWasmAbi,)*
R: ReturnWasmAbi,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
// Raw &dyn Fn/&dyn FnMut passed as arguments use the catching
// invoke shim by default, matching the previous runtime behavior.
<Self as WasmClosure>::describe_invoke::<true>();
}
}
unsafe impl<'__closure, $($var,)* R> WasmClosure for dyn $Fn $FnArgs -> R + '__closure
where
$($var: $FromWasmAbi,)*
R: ReturnWasmAbi,
{
const IS_MUT: bool = $is_mut;
type Static = dyn $Fn $FnArgs -> R;
type AsMut = dyn FnMut $FnArgs -> R + '__closure;
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe_invoke<const UNWIND_SAFE: bool>() {
inform(FUNCTION);
inform(invoke::<$($var,)* R, UNWIND_SAFE> as *const () as usize as u32);
closures!(@describe $FnArgs);
R::describe();
R::describe();
}
}
impl<T, $($var,)* R> IntoWasmClosure<dyn $Fn $FnArgs -> R> for T
where
T: 'static + $Fn $FnArgs -> R,
{
fn unsize(self: Box<Self>) -> Box<dyn $Fn $FnArgs -> R> { self }
}
};);
// IntoWasmClosureRef is only implemented for Fn, not FnMut.
// IntoWasmClosureRefMut is implemented for FnMut.
// Since Fn: FnMut, any Fn closure can be used as FnMut, so this covers all cases.
(@impl_unsize_closure_ref $FnArgs:tt $FromWasmAbi:ident $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => (
impl<'a, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRef<dyn Fn $FnArgs -> R + 'a> for T
where
T: Fn $FnArgs -> R,
{
fn unsize_closure_ref(&self) -> &(dyn Fn $FnArgs -> R + 'a) { self }
}
impl<'a, T: 'a, $($var: 'a + $FromWasmAbi,)* R: 'a + ReturnWasmAbi> IntoWasmClosureRefMut<dyn FnMut $FnArgs -> R + 'a> for T
where
T: FnMut $FnArgs -> R,
{
fn unsize_closure_ref(&mut self) -> &mut (dyn FnMut $FnArgs -> R + 'a) { self }
}
);
(@impl_for_args $FnArgs:tt $FromWasmAbi:ident [$($maybe_unwind_safe:tt)*] $($var_expr:expr => $var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) => {
closures!(@impl_for_fn false [] Fn $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
closures!(@impl_for_fn true [mut] FnMut $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
closures!(@impl_unsize_closure_ref $FnArgs $FromWasmAbi $($var_expr => $var $arg1 $arg2 $arg3 $arg4)*);
// 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.
#[allow(non_snake_case, unused_parens)]
impl<T, $($var,)* R> WasmClosureFnOnce<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
where
T: 'static + (FnOnce $FnArgs -> R),
$($var: $FromWasmAbi + 'static,)*
R: ReturnWasmAbi + 'static,
$($maybe_unwind_safe)*
{
fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
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 rc1 = Rc::new(WasmRefCell::new(None));
let rc2 = rc1.clone();
let closure = Closure::once(closures!(@closure $FnArgs $($var)* {
let result = self($($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
}));
let js_val = closure.as_ref().clone();
*rc1.borrow_mut() = Some(closure);
debug_assert_eq!(Rc::strong_count(&rc1), 2);
drop(rc1);
js_val
}
}
#[allow(non_snake_case, unused_parens)]
impl<T, $($var,)* R> WasmClosureFnOnceAbort<dyn FnMut $FnArgs -> R, $FnArgs, R> for T
where
T: 'static + (FnOnce $FnArgs -> R),
$($var: $FromWasmAbi + 'static,)*
R: ReturnWasmAbi + 'static,
{
fn into_fn_mut(self) -> Box<dyn FnMut $FnArgs -> R> {
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 rc1 = Rc::new(WasmRefCell::new(None));
let rc2 = rc1.clone();
// TODO: Unwind safety for FnOnce
let closure = Closure::once_aborting(closures!(@closure $FnArgs $($var)* {
let result = self($($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
}));
let js_val = closure.as_ref().clone();
*rc1.borrow_mut() = Some(closure);
debug_assert_eq!(Rc::strong_count(&rc1), 2);
drop(rc1);
js_val
}
}
};
([$($unwind_safe:tt)*] $( ($($var:ident $arg1:ident $arg2:ident $arg3:ident $arg4:ident)*) )*) => ($(
closures!(@impl_for_args ($($var),*) FromWasmAbi [$($maybe_unwind_safe)*] $($var::from_abi($var) => $var $arg1 $arg2 $arg3 $arg4)*);
)*);
}
#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
closures! {
[T: core::panic::UnwindSafe,]
()
(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)
}
#[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
closures! {
[]
()
(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)
}
// Comprehensive type-safe cross-function covariant and contravariant casting rules
macro_rules! impl_fn_upcasts {
() => {
impl_fn_upcasts!(@arities
[0 []]
[1 [A1 B1] O1]
[2 [A1 B1 A2 B2] O2]
[3 [A1 B1 A2 B2 A3 B3] O3]
[4 [A1 B1 A2 B2 A3 B3 A4 B4] O4]
[5 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5] O5]
[6 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6] O6]
[7 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7] O7]
[8 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8] O8]
);
};
(@arities) => {};
(@arities [$n:tt $args:tt $($opt:ident)?] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
impl_fn_upcasts!(@same $args);
impl_fn_upcasts!(@cross_all $args [] $([$rest_n $rest_args $($rest_opt)?])*);
impl_fn_upcasts!(@arities $([$rest_n $rest_args $($rest_opt)?])*);
};
(@same []) => {
impl<R1, R2> UpcastFrom<fn() -> R1> for fn() -> R2
where
R2: UpcastFrom<R1>
{}
impl<'a, R1, R2> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn() -> R2 + 'a
where
R2: UpcastFrom<R1>
{}
impl<'a, R1, R2> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut() -> R2 + 'a
where
R2: UpcastFrom<R1>
{}
};
// Arguments implemented with contravariance
(@same [$($A1:ident $A2:ident)+]) => {
impl<R1, R2, $($A1, $A2),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2),+) -> R2
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
{}
impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
{}
impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
{}
};
// Cross-all: done
(@cross_all $args:tt $opts:tt) => {};
// Cross-all: process next
(@cross_all $args:tt [$($opts:ident)*] [$next_n:tt $next_args:tt $next_opt:ident] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
impl_fn_upcasts!(@extend $args [$($opts)* $next_opt]);
impl_fn_upcasts!(@shrink $args [$($opts)* $next_opt]);
impl_fn_upcasts!(@cross_all $args [$($opts)* $next_opt] $([$rest_n $rest_args $($rest_opt)?])*);
};
// Extend: 0 -> N
(@extend [] [$($O:ident)+]) => {
impl<R1, R2, $($O),+> UpcastFrom<fn() -> R1> for fn($($O),+) -> R2
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn($($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut($($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<Undefined>,)+
{}
};
// Extend: N -> M
(@extend [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2,)+ $($O),+) -> R2
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+ // Contravariant
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2,)+ $($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+ // Contravariant
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2,)+ $($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+ // Contravariant
$($O: UpcastFrom<Undefined>,)+
{}
};
// Shrink: N -> 0
(@shrink [] [$($O:ident)+]) => {
impl<R1, R2, $($O),+> UpcastFrom<fn($($O),+) -> R1> for fn() -> R2
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn($($O),+) -> R1 + 'a> for dyn Fn() -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut($($O),+) -> R1 + 'a> for dyn FnMut() -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<Undefined>,)+
{}
};
// Shrink: M -> N
(@shrink [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1,)+ $($O),+) -> R1> for fn($($A2),+) -> R2
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+ // Contravariant
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1,)+ $($O),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+ // Contravariant
$($O: UpcastFrom<Undefined>,)+
{}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1,)+ $($O),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+ // Contravariant
$($O: UpcastFrom<Undefined>,)+
{}
};
}
impl_fn_upcasts!();
// 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.
// We need to allow coherence leak check just for these traits because we're providing separate implementation for `Fn(&A)` variants when `Fn(A)` one already exists.
#[allow(coherence_leak_check)]
const _: () = {
#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
closures!(@impl_for_args (&A) RefFromWasmAbi [T: core::panic::UnwindSafe,] &*A::ref_from_abi(A) => A a1 a2 a3 a4);
#[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
closures!(@impl_for_args (&A) RefFromWasmAbi [] &*A::ref_from_abi(A) => A a1 a2 a3 a4);
};
// UpcastFrom impl for ScopedClosure.
// ScopedClosure<T1> upcasts to ScopedClosure<T2> when the underlying closure type T1 upcasts to T2.
// The dyn Fn/FnMut UpcastFrom impls above encode correct variance (covariant return, contravariant args).
//
// The 'a: 'b bound is critical for soundness: it ensures the target lifetime 'b does not
// exceed the source lifetime 'a. Without it, upcast_into could fabricate a
// ScopedClosure<'static, _> from a short-lived ScopedClosure, enabling use-after-free.
impl<'a: 'b, 'b, T1, T2> UpcastFrom<ScopedClosure<'a, T1>> for ScopedClosure<'b, T2>
where
T1: ?Sized + WasmClosure,
T2: ?Sized + WasmClosure + UpcastFrom<T1>,
{
}

841
vendor/wasm-bindgen/src/convert/impls.rs vendored Normal file
View File

@@ -0,0 +1,841 @@
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::char;
use core::mem::{self, ManuallyDrop};
use core::ptr::NonNull;
use crate::__rt::marker::ErasableGeneric;
use crate::convert::traits::{WasmAbi, WasmPrimitive};
use crate::convert::{
FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi,
RefFromWasmAbi, ReturnWasmAbi, TryFromJsValue, UpcastFrom,
};
use crate::sys::Promising;
use crate::sys::{JsOption, Undefined};
use crate::{Clamped, JsError, JsValue, UnwrapThrowExt};
// Primitive types can always be passed over the ABI.
impl<T: WasmPrimitive> 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<T: WasmAbi<Prim4 = ()>> WasmAbi for Option<T> {
/// 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)
}
}
impl UpcastFrom<$t> for JsValue {}
impl UpcastFrom<$t> for JsOption<JsValue> {}
impl UpcastFrom<$t> for $t {}
)*)
}
type_wasm_native!(
i64 as i64
u64 as u64
i128 as i128
u128 as u128
f64 as f64
);
impl UpcastFrom<u64> for u128 {}
impl UpcastFrom<u64> for JsOption<u128> {}
impl UpcastFrom<i64> for i128 {}
impl UpcastFrom<i64> for JsOption<i128> {}
/// 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 }
}
unsafe impl ErasableGeneric for $t {
type Repr = $t;
}
impl Promising for $t {
type Resolution = $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)
}
}
}
impl UpcastFrom<$t> for JsValue {}
impl UpcastFrom<$t> for JsOption<JsValue> {}
impl UpcastFrom<$t> for $t {}
)*)
}
type_wasm_native_f64_option!(
i32 as i32
isize as i32
u32 as u32
usize as u32
f32 as f32
);
#[cfg(target_pointer_width = "32")]
impl UpcastFrom<isize> for i32 {}
#[cfg(target_pointer_width = "32")]
impl UpcastFrom<isize> for JsOption<i32> {}
impl UpcastFrom<isize> for i64 {}
impl UpcastFrom<isize> for JsOption<i64> {}
impl UpcastFrom<isize> for i128 {}
impl UpcastFrom<isize> for JsOption<i128> {}
impl UpcastFrom<i32> for isize {}
impl UpcastFrom<i32> for JsOption<isize> {}
impl UpcastFrom<i32> for i64 {}
impl UpcastFrom<i32> for JsOption<i64> {}
impl UpcastFrom<i32> for i128 {}
impl UpcastFrom<i32> for JsOption<i128> {}
impl UpcastFrom<u32> for usize {}
impl UpcastFrom<u32> for JsOption<usize> {}
impl UpcastFrom<u32> for u64 {}
impl UpcastFrom<u32> for JsOption<u64> {}
impl UpcastFrom<u32> for u128 {}
impl UpcastFrom<u32> for JsOption<u128> {}
#[cfg(target_pointer_width = "32")]
impl UpcastFrom<usize> for u32 {}
#[cfg(target_pointer_width = "32")]
impl UpcastFrom<usize> for JsOption<u32> {}
impl UpcastFrom<usize> for u64 {}
impl UpcastFrom<usize> for JsOption<u64> {}
impl UpcastFrom<usize> for u128 {}
impl UpcastFrom<usize> for JsOption<u128> {}
impl UpcastFrom<f32> for f64 {}
impl UpcastFrom<f32> for JsOption<f64> {}
/// 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 }
}
unsafe impl ErasableGeneric for $t {
type Repr = $t;
}
impl Promising for $t {
type Resolution = $t;
}
impl UpcastFrom<$t> for JsValue {}
impl UpcastFrom<$t> for JsOption<JsValue> {}
impl UpcastFrom<$t> for $t {}
)*)
}
type_abi_as_u32!(i8 u8 i16 u16);
impl UpcastFrom<i8> for i16 {}
impl UpcastFrom<i8> for JsOption<i16> {}
impl UpcastFrom<i8> for i32 {}
impl UpcastFrom<i8> for JsOption<i32> {}
impl UpcastFrom<i8> for i64 {}
impl UpcastFrom<i8> for JsOption<i64> {}
impl UpcastFrom<i8> for i128 {}
impl UpcastFrom<i8> for JsOption<i128> {}
impl UpcastFrom<u8> for u16 {}
impl UpcastFrom<u8> for JsOption<u16> {}
impl UpcastFrom<u8> for u32 {}
impl UpcastFrom<u8> for JsOption<u32> {}
impl UpcastFrom<u8> for u64 {}
impl UpcastFrom<u8> for JsOption<u64> {}
impl UpcastFrom<u8> for u128 {}
impl UpcastFrom<u8> for JsOption<u128> {}
impl UpcastFrom<i16> for i32 {}
impl UpcastFrom<i16> for JsOption<i32> {}
impl UpcastFrom<i16> for i64 {}
impl UpcastFrom<i16> for JsOption<i64> {}
impl UpcastFrom<i16> for i128 {}
impl UpcastFrom<i16> for JsOption<i128> {}
impl UpcastFrom<u16> for u32 {}
impl UpcastFrom<u16> for JsOption<u32> {}
impl UpcastFrom<u16> for u64 {}
impl UpcastFrom<u16> for JsOption<u64> {}
impl UpcastFrom<u16> for u128 {}
impl UpcastFrom<u16> for JsOption<u128> {}
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
}
}
unsafe impl ErasableGeneric for bool {
type Repr = bool;
}
impl Promising for bool {
type Resolution = bool;
}
impl UpcastFrom<bool> for JsValue {}
impl UpcastFrom<bool> for JsOption<JsValue> {}
impl UpcastFrom<bool> for bool {}
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
}
}
unsafe impl ErasableGeneric for char {
type Repr = char;
}
impl Promising for char {
type Resolution = char;
}
impl UpcastFrom<char> for JsValue {}
impl UpcastFrom<char> for JsOption<JsValue> {}
impl UpcastFrom<char> for char {}
impl<T> IntoWasmAbi for *const T {
type Abi = u32;
#[inline]
fn into_abi(self) -> u32 {
self as u32
}
}
impl<T> FromWasmAbi for *const T {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32) -> *const T {
js as *const T
}
}
unsafe impl<T: ErasableGeneric> ErasableGeneric for *const T {
type Repr = *const T::Repr;
}
impl<T, Target> UpcastFrom<*const T> for *const Target where Target: UpcastFrom<T> {}
impl<T, Target> UpcastFrom<*const T> for JsOption<*const Target> where Target: UpcastFrom<T> {}
impl<T> 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)
}
}
unsafe impl<T: ErasableGeneric> ErasableGeneric for Option<T> {
type Repr = Option<<T as ErasableGeneric>::Repr>;
}
impl<T, Target> UpcastFrom<Option<T>> for Option<Target> where Target: UpcastFrom<T> {}
impl<T, Target> UpcastFrom<Option<T>> for JsOption<Option<Target>> where Target: UpcastFrom<T> {}
impl<T> 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<T> IntoWasmAbi for *mut T {
type Abi = u32;
#[inline]
fn into_abi(self) -> u32 {
self as u32
}
}
impl<T> FromWasmAbi for *mut T {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: u32) -> *mut T {
js as *mut T
}
}
impl<T> 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<T> 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<T> IntoWasmAbi for NonNull<T> {
type Abi = u32;
#[inline]
fn into_abi(self) -> u32 {
self.as_ptr() as u32
}
}
impl<T> OptionIntoWasmAbi for NonNull<T> {
#[inline]
fn none() -> u32 {
0
}
}
impl<T> FromWasmAbi for NonNull<T> {
type Abi = u32;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
// SAFETY: Checked in bindings.
NonNull::new_unchecked(js as *mut T)
}
}
impl<T> OptionFromWasmAbi for NonNull<T> {
#[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<JsValue>;
#[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 OptionIntoWasmAbi for JsValue {
#[inline]
fn none() -> u32 {
crate::__rt::JSIDX_UNDEFINED
}
}
impl OptionIntoWasmAbi for &JsValue {
#[inline]
fn none() -> u32 {
crate::__rt::JSIDX_UNDEFINED
}
}
impl OptionFromWasmAbi for JsValue {
#[inline]
fn is_none(js: &u32) -> bool {
unsafe { Self::ref_from_abi(*js) }.is_undefined()
}
}
impl<T: OptionIntoWasmAbi> IntoWasmAbi for Option<T> {
type Abi = T::Abi;
#[inline]
fn into_abi(self) -> T::Abi {
match self {
None => T::none(),
Some(me) => me.into_abi(),
}
}
}
impl<T: OptionFromWasmAbi> FromWasmAbi for Option<T> {
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<T: OptionIntoWasmAbi + ErasableGeneric<Repr = JsValue> + Promising> Promising for Option<T> {
type Resolution = Option<<T as Promising>::Resolution>;
}
impl<T: IntoWasmAbi> IntoWasmAbi for Clamped<T> {
type Abi = T::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
self.0.into_abi()
}
}
impl<T: FromWasmAbi> FromWasmAbi for Clamped<T> {
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 FromWasmAbi for () {
type Abi = ();
#[inline]
unsafe fn from_abi(_js: ()) {}
}
impl Promising for () {
type Resolution = Undefined;
}
impl UpcastFrom<()> for JsValue {}
impl UpcastFrom<()> for () {}
unsafe impl ErasableGeneric for () {
type Repr = ();
}
impl<T: WasmAbi<Prim3 = (), Prim4 = ()>> WasmAbi for Result<T, u32> {
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<T, E> ReturnWasmAbi for Result<T, E>
where
T: IntoWasmAbi,
E: Into<JsValue>,
T::Abi: WasmAbi<Prim3 = (), Prim4 = ()>,
{
type Abi = Result<T::Abi, u32>;
#[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())
}
}
}
}
unsafe impl<T: ErasableGeneric, E: ErasableGeneric> ErasableGeneric for Result<T, E> {
type Repr = Result<<T as ErasableGeneric>::Repr, <E as ErasableGeneric>::Repr>;
}
impl<T: ErasableGeneric + Promising, E: ErasableGeneric> Promising for Result<T, E> {
type Resolution = Result<<T as Promising>::Resolution, E>;
}
impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for Result<TargetT, TargetE>
where
TargetT: UpcastFrom<T>,
TargetE: UpcastFrom<E>,
{
}
impl<T, E, TargetT, TargetE> UpcastFrom<Result<T, E>> for JsOption<Result<TargetT, TargetE>>
where
TargetT: UpcastFrom<T>,
TargetE: UpcastFrom<E>,
{
}
unsafe impl ErasableGeneric for JsError {
type Repr = JsValue;
}
impl IntoWasmAbi for JsError {
type Abi = <JsValue as IntoWasmAbi>::Abi;
fn into_abi(self) -> Self::Abi {
self.value.into_abi()
}
}
impl Promising for JsError {
type Resolution = JsError;
}
impl UpcastFrom<JsError> for JsValue {}
impl UpcastFrom<JsError> for JsOption<JsValue> {}
impl UpcastFrom<JsError> for JsError {}
/// # ⚠️ 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<JsValue>` impl needs
// ownership of `T`.
pub fn js_value_vector_into_abi<T: Into<JsValue>>(
vector: Box<[T]>,
) -> <Box<[JsValue]> 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<T: TryFromJsValue>(
js: <Box<[JsValue]> as FromWasmAbi>::Abi,
) -> Box<[T]> {
let js_vals = <Vec<JsValue> 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()
}

15
vendor/wasm-bindgen/src/convert/mod.rs vendored Normal file
View File

@@ -0,0 +1,15 @@
//! # ⚠️ 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::*;

View File

@@ -0,0 +1,505 @@
use 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::__rt::marker::ErasableGeneric;
use crate::__wbindgen_copy_to_typed_array;
use crate::convert::{
js_value_vector_from_abi, js_value_vector_into_abi, FromWasmAbi, IntoWasmAbi,
LongRefFromWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi,
UpcastFrom, 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<WasmSlice>`.
#[repr(C)]
#[derive(Clone, Copy)]
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<T> {
/// A copy of the data in the JS typed array.
contents: Box<[T]>,
/// A reference to the original JS typed array.
js: JsValue,
}
impl<T> Drop for MutSlice<T> {
fn drop(&mut self) {
let byte_slice = unsafe {
core::slice::from_raw_parts(
self.contents.as_ptr() as *const u8,
self.contents.len() * mem::size_of::<T>(),
)
};
__wbindgen_copy_to_typed_array(byte_slice, &self.js);
}
}
impl<T> Deref for MutSlice<T> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.contents
}
}
impl<T> DerefMut for MutSlice<T> {
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]> {
<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 = <Box<[$t]>>::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 = <Box<[JsValue]> as IntoWasmAbi>::Abi;
fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi {
js_value_vector_into_abi(vector)
}
}
impl VectorFromWasmAbi for String {
type Abi = <Box<[JsValue]> 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<WasmSlice> {
// 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<WasmSlice> {
None
}
}
}
impl<T> IntoWasmAbi for Vec<T>
where
Box<[T]>: IntoWasmAbi<Abi = WasmSlice>,
{
type Abi = <Box<[T]> as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
self.into_boxed_slice().into_abi()
}
}
impl<T> OptionIntoWasmAbi for Vec<T>
where
Box<[T]>: IntoWasmAbi<Abi = WasmSlice>,
{
#[inline]
fn none() -> WasmSlice {
null_slice()
}
}
impl<T> FromWasmAbi for Vec<T>
where
Box<[T]>: FromWasmAbi<Abi = WasmSlice>,
{
type Abi = <Box<[T]> as FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
<Box<[T]>>::from_abi(js).into()
}
}
impl<T> OptionFromWasmAbi for Vec<T>
where
Box<[T]>: FromWasmAbi<Abi = WasmSlice>,
{
#[inline]
fn is_none(abi: &WasmSlice) -> bool {
abi.ptr == 0
}
}
impl IntoWasmAbi for String {
type Abi = <Vec<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.into_bytes().into_abi())
}
}
impl OptionIntoWasmAbi for String {
#[inline]
fn none() -> Self::Abi {
null_slice()
}
}
impl FromWasmAbi for String {
type Abi = <Vec<u8> as FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
String::from_utf8_unchecked(<Vec<u8>>::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<str>;
#[inline]
unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
mem::transmute::<Box<[u8]>, Box<str>>(<Box<[u8]>>::from_abi(js))
}
}
impl LongRefFromWasmAbi for str {
type Abi = <[u8] as RefFromWasmAbi>::Abi;
type Anchor = Box<str>;
#[inline]
unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
Self::ref_from_abi(js)
}
}
unsafe impl ErasableGeneric for &str {
type Repr = &'static str;
}
unsafe impl<T: ErasableGeneric> ErasableGeneric for Box<[T]> {
type Repr = Box<[T::Repr]>;
}
impl UpcastFrom<&str> for &str {}
impl<T, Target> UpcastFrom<Box<[T]>> for Box<[Target]> where Target: UpcastFrom<T> {}
unsafe impl<T: ErasableGeneric> ErasableGeneric for Vec<T> {
type Repr = Vec<T::Repr>;
}
impl<T, Target> UpcastFrom<Vec<T>> for Vec<Target> where Target: UpcastFrom<T> {}
impl<T: VectorIntoWasmAbi> IntoWasmAbi for Box<[T]> {
type Abi = <T as VectorIntoWasmAbi>::Abi;
fn into_abi(self) -> Self::Abi {
T::vector_into_abi(self)
}
}
impl<T> OptionIntoWasmAbi for Box<[T]>
where
Self: IntoWasmAbi<Abi = WasmSlice>,
{
fn none() -> WasmSlice {
null_slice()
}
}
impl<T: VectorFromWasmAbi> FromWasmAbi for Box<[T]> {
type Abi = <T as VectorFromWasmAbi>::Abi;
unsafe fn from_abi(js: Self::Abi) -> Self {
T::vector_from_abi(js)
}
}
impl<T> OptionFromWasmAbi for Box<[T]>
where
Self: FromWasmAbi<Abi = WasmSlice>,
{
fn is_none(slice: &WasmSlice) -> bool {
slice.ptr == 0
}
}
impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> VectorFromWasmAbi for T {
type Abi = WasmSlice;
#[inline]
unsafe fn vector_from_abi(js: WasmSlice) -> Box<[Self]> {
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<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> 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,
}
}
}
// JsValue-like slice support (Rust-to-JS only)
// JsValue-like are repr(transparent) over u32, so &[JsValue] is a contiguous array of heap indices
unsafe impl<T: ErasableGeneric> ErasableGeneric for &[T] {
type Repr = &'static [T::Repr];
}
impl<'a, T, Target> UpcastFrom<&'a [T]> for &'a [Target] where Target: UpcastFrom<T> {}
impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> IntoWasmAbi for &[T] {
type Abi = WasmSlice;
#[inline]
fn into_abi(self) -> WasmSlice {
WasmSlice {
ptr: self.as_ptr() as u32,
len: self.len() as u32,
}
}
}
impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> OptionIntoWasmAbi for &[T] {
#[inline]
fn none() -> WasmSlice {
null_slice()
}
}

View File

@@ -0,0 +1,540 @@
use core::borrow::Borrow;
use core::ops::{Deref, DerefMut};
use core::panic::AssertUnwindSafe;
use crate::describe::*;
use crate::sys::JsOption;
use crate::{ErasableGeneric, 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 `<Self as
/// IntoWasmAbi>::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<Target = Self>;
/// 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<Self>;
/// 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<Target = Self>;
/// 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<Self>`.
///
/// This trait is used when implementing `IntoWasmAbi for Option<T>`.
///
/// # ⚠️ 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<Self>`.
///
/// This trait is used when implementing `FromWasmAbi for Option<T>`.
///
/// # ⚠️ 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<T, JsValue>` 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<T: IntoWasmAbi> 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<T: WasmAbi> {
prim1: T::Prim1,
prim2: T::Prim2,
prim3: T::Prim3,
prim4: T::Prim4,
}
impl<T: WasmAbi> From<T> for WasmRet<T> {
fn from(value: T) -> Self {
let (prim1, prim2, prim3, prim4) = value.split();
Self {
prim1,
prim2,
prim3,
prim4,
}
}
}
// Ideally this'd just be an `Into<T>` implementation, but unfortunately that
// doesn't work because of the orphan rule.
impl<T: WasmAbi> WasmRet<T> {
/// 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.
///
/// The semantics of this trait for various types are designed to provide a runtime
/// analog of the static semantics implemented by the IntoWasmAbi function bindgen,
/// with the exception that conversions are constrained to not cast invalid types.
///
/// For example, where the Wasm static semantics will permit `foo(x: i32)` when passed
/// from JS `foo("5")` to treat that as `foo(5)`, this trait will instead throw. Apart
/// from these reduced type conversion cases, behaviours should otherwise match the
/// static semantics.
///
/// 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 {
/// Performs the conversion.
fn try_from_js_value(value: JsValue) -> Result<Self, JsValue> {
Self::try_from_js_value_ref(&value).ok_or(value)
}
/// Performs the conversion.
fn try_from_js_value_ref(value: &JsValue) -> Option<Self>;
}
impl<T: FromWasmAbi> FromWasmAbi for AssertUnwindSafe<T> {
type Abi = T::Abi;
unsafe fn from_abi(js: Self::Abi) -> Self {
AssertUnwindSafe(T::from_abi(js))
}
}
/// A trait for defining upcast relationships from a source type.
///
/// This is the inverse of [`Upcast<T>`] - instead of implementing
/// `impl Upcast<Target> for Source`, you implement `impl UpcastFrom<Source> for Target`.
///
/// # Why UpcastFrom?
///
/// This resolves Rust's orphan rule issues: you can implement `UpcastFrom<MyType>`
/// for external types when `MyType` is local to your crate, whereas implementing
/// `Upcast<ExternalType>` would be prohibited by orphan rules.
///
/// # ⚠️ 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.
///
/// # Relationship to Upcast
///
/// `UpcastFrom<S>` provides a blanket implementation of `Upcast<T>`:
/// ```ignore
/// impl<S, T> Upcast<T> for S where T: UpcastFrom<S> {}
/// ```
///
/// This means implementing `UpcastFrom<Source> for Target` automatically gives you
/// `Upcast<Target> for Source`, enabling `source.upcast()` to produce `Target`.
pub trait UpcastFrom<S: ?Sized> {}
/// A trait for type-safe generic upcasting.
///
/// # ⚠️ 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
///
/// `Upcast<T>` has a blanket implementation for all types where `T: UpcastFrom<Self>`.
/// New upcast relationships should typically be defined by implementing `FromUpcast`
/// rather than `Upcast` directly, to avoid orphan rule issues.
pub trait Upcast<T: ?Sized> {
/// Perform a zero-cost type-safe upcast to a wider ref type within the Wasm
/// bindgen generics type system.
///
/// This enables proper nested conversions that obey subtyping rules,
/// supporting strict API type checking.
///
/// The common pattern when passing a narrow type is to call `upcast()`
/// or `upcast_into()` to obtain the correct type for the function usage,
/// while ensuring safe type checked usage.
///
/// For example, if passing `Promise<Number>` as an argument to a function
/// where `Promise<JsValue>` is expected, or `Function<JsValue>` as an
/// argument where `Function<Number>` is expected.
///
/// This is a compile time conversion only by the nature of the erasable
/// generics type system.
#[inline]
fn upcast(&self) -> &T
where
Self: ErasableGeneric,
T: Sized + ErasableGeneric<Repr = <Self as ErasableGeneric>::Repr>,
{
unsafe { &*(self as *const Self as *const T) }
}
/// Perform a zero-cost type-safe upcast to a wider type within the Wasm
/// bindgen generics type system.
///
/// This enables proper nested conversions that obey subtyping rules,
/// supporting strict API type checking.
///
/// The common pattern when passing a narrow type is to call `upcast()`
/// or `upcast_into()` to obtain the correct type for the function usage,
/// while ensuring safe type checked usage.
///
/// For example, if passing `Promise<Number>` as an argument to a function
/// where `Promise<JsValue>` is expected, or `FunctionArgs<JsValue>` as an
/// argument where `FunctionArgs<Number>` is expected.
///
/// This is a compile time conversion only by the nature of the erasable
/// generics type system.
#[inline]
fn upcast_into(self) -> T
where
Self: Sized + ErasableGeneric,
T: Sized + ErasableGeneric<Repr = <Self as ErasableGeneric>::Repr>,
{
unsafe { core::mem::transmute_copy(&core::mem::ManuallyDrop::new(self)) }
}
}
// Blanket impl: UpcastFrom<S> for T implies Upcast<T> for S
impl<S, T> Upcast<T> for S
where
T: UpcastFrom<S> + ?Sized,
S: ?Sized,
{
}
// Reference impls using UpcastFrom
impl<'a, T, Target> UpcastFrom<&'a mut T> for &'a mut Target where Target: UpcastFrom<T> {}
impl<'a, T, Target> UpcastFrom<&'a T> for &'a Target where Target: UpcastFrom<T> {}
// Tuple upcasts with structural covariance
macro_rules! impl_tuple_upcast {
([$($T:ident)+] [$($Target:ident)+]) => {
// Structural covariance: (T...) -> (Target...)
impl<$($T,)+ $($Target,)+> UpcastFrom<($($T,)+)> for ($($Target,)+)
where
$($Target: JsGeneric + UpcastFrom<$T>,)+
$($T: JsGeneric,)+
{
}
impl<$($T: JsGeneric,)+ $($Target: JsGeneric,)+> UpcastFrom<($($T,)+)> for JsOption<($($Target,)+)>
where
$($Target: JsGeneric + UpcastFrom<$T>,)+
$($T: JsGeneric,)+
{
}
};
}
impl_tuple_upcast!([T1][Target1]);
impl_tuple_upcast!([T1 T2] [Target1 Target2]);
impl_tuple_upcast!([T1 T2 T3] [Target1 Target2 Target3]);
impl_tuple_upcast!([T1 T2 T3 T4] [Target1 Target2 Target3 Target4]);
impl_tuple_upcast!([T1 T2 T3 T4 T5] [Target1 Target2 Target3 Target4 Target5]);
impl_tuple_upcast!([T1 T2 T3 T4 T5 T6] [Target1 Target2 Target3 Target4 Target5 Target6]);
impl_tuple_upcast!([T1 T2 T3 T4 T5 T6 T7] [Target1 Target2 Target3 Target4 Target5 Target6 Target7]);
impl_tuple_upcast!([T1 T2 T3 T4 T5 T6 T7 T8] [Target1 Target2 Target3 Target4 Target5 Target6 Target7 Target8]);
/// A convenience trait for types that erase to [`JsValue`].
///
/// This is a shorthand for `ErasableGeneric<Repr = JsValue>`, used as a bound
/// on generic parameters that must be representable as JavaScript values.
///
/// # When to Use
///
/// Use `JsGeneric` as a trait bound when you need a generic type that:
/// - Can be passed to/from JavaScript
/// - Is type-erased to `JsValue` at the FFI boundary
///
/// # Examples
///
/// ```ignore
/// use wasm_bindgen::JsGeneric;
///
/// fn process_js_values<T: JsGeneric>(items: &[T]) {
/// // T can be any JS-compatible type
/// }
/// ```
///
/// # Implementors
///
/// This trait is automatically implemented for all types that implement
/// `ErasableGeneric<Repr = JsValue>`, including:
/// - All `js_sys` types (`Object`, `Array`, `Function`, etc.)
/// - `JsValue` itself
/// - Custom types imported via `#[wasm_bindgen]`
pub trait JsGeneric:
ErasableGeneric<Repr = JsValue> + UpcastFrom<Self> + Upcast<Self> + Upcast<JsValue> + 'static
{
}
impl<T: ErasableGeneric<Repr = JsValue> + UpcastFrom<T> + Upcast<JsValue> + 'static> JsGeneric
for T
{
}

210
vendor/wasm-bindgen/src/describe.rs vendored Normal file
View File

@@ -0,0 +1,210 @@
//! 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::panic::AssertUnwindSafe;
use core::{mem::MaybeUninit, ptr::NonNull};
use crate::{Clamped, JsError, JsValue, __rt::marker::ErasableGeneric};
use cfg_if::cfg_if;
pub use wasm_bindgen_shared::tys::*;
#[inline(always)] // see the wasm-interpreter module
#[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<T> WasmDescribe for *const T {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(U32)
}
}
impl<T> WasmDescribe for *mut T {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(U32)
}
}
impl<T> WasmDescribe for NonNull<T> {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(NONNULL)
}
}
impl<T: WasmDescribe> WasmDescribe for [T] {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(SLICE);
T::describe();
}
}
impl<T: WasmDescribe + ?Sized> WasmDescribe for &T {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(REF);
T::describe();
}
}
impl<T: WasmDescribe + ?Sized> 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<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> WasmDescribeVector for T {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe_vector() {
inform(VECTOR);
T::describe();
}
}
impl<T: WasmDescribeVector> WasmDescribe for Box<[T]> {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
T::describe_vector();
}
}
impl<T> WasmDescribe for Vec<T>
where
Box<[T]>: WasmDescribe,
{
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
<Box<[T]>>::describe();
}
}
impl<T: WasmDescribe> WasmDescribe for Option<T> {
#[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<T: WasmDescribe, E: Into<JsValue>> WasmDescribe for Result<T, E> {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(RESULT);
T::describe();
}
}
impl<T: WasmDescribe> WasmDescribe for MaybeUninit<T> {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
T::describe();
}
}
impl<T: WasmDescribe> WasmDescribe for Clamped<T> {
#[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();
}
}
impl<T> WasmDescribe for AssertUnwindSafe<T>
where
T: WasmDescribe,
{
fn describe() {
T::describe();
}
}

154
vendor/wasm-bindgen/src/externref.rs vendored Normal file
View File

@@ -0,0 +1,154 @@
use crate::JsValue;
use crate::__rt;
use alloc::slice;
use alloc::vec::Vec;
use core::cell::RefCell;
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) -> ();
}
}
struct Slab {
data: Vec<usize>,
head: usize,
base: usize,
}
impl Slab {
const fn new() -> Self {
Self {
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_attr(target_feature = "atomics", thread_local)]
static HEAP_SLAB: __rt::ThreadLocalWrapper<RefCell<Slab>> =
__rt::ThreadLocalWrapper(RefCell::new(Slab::new()));
#[no_mangle]
pub extern "C" fn __externref_table_alloc() -> usize {
HEAP_SLAB.0.borrow_mut().alloc()
}
#[no_mangle]
pub extern "C" fn __externref_table_dealloc(idx: usize) {
if idx < __rt::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.0.borrow_mut().dealloc(idx)
}
#[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`.
pub fn __wbindgen_externref_heap_live_count() -> u32 {
HEAP_SLAB.0.borrow_mut().live_count()
}

1853
vendor/wasm-bindgen/src/lib.rs vendored Normal file

File diff suppressed because it is too large Load Diff

4
vendor/wasm-bindgen/src/link.rs vendored Normal file
View File

@@ -0,0 +1,4 @@
// 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() {}

142
vendor/wasm-bindgen/src/rt/marker.rs vendored Normal file
View File

@@ -0,0 +1,142 @@
/// Marker trait for types that support `#[wasm_bindgen(constructor)]`.
#[cfg_attr(
wbg_diagnostic,
diagnostic::on_unimplemented(
message = "JavaScript constructors are not supported for `{Self}`",
label = "this function cannot be the constructor of `{Self}`",
note = "`#[wasm_bindgen(constructor)]` is only supported for `struct`s and cannot be used for `enum`s.",
note = "Consider removing the `constructor` option and using a regular static method instead."
)
)]
pub trait SupportsConstructor {}
pub struct CheckSupportsConstructor<T: SupportsConstructor>(T);
/// Marker trait for types that support `#[wasm_bindgen(getter)]` or
/// `#[wasm_bindgen(Setter)]` on instance methods.
#[cfg_attr(
wbg_diagnostic,
diagnostic::on_unimplemented(
message = "JavaScript instance getters and setters are not supported for `{Self}`",
label = "this method cannot be a getter or setter for `{Self}`",
note = "`#[wasm_bindgen(getter)]` and `#[wasm_bindgen(setter)]` are only supported for `struct`s and cannot be used for `enum`s.",
)
)]
pub trait SupportsInstanceProperty {}
pub struct CheckSupportsInstanceProperty<T: SupportsInstanceProperty>(T);
/// Marker trait for types that support `#[wasm_bindgen(getter)]` or
/// `#[wasm_bindgen(Setter)]` on static methods.
#[cfg_attr(
wbg_diagnostic,
diagnostic::on_unimplemented(
message = "JavaScript static getters and setters are not supported for `{Self}`",
label = "this static function cannot be a static getter or setter on `{Self}`",
note = "`#[wasm_bindgen(getter)]` and `#[wasm_bindgen(setter)]` are only supported for `struct`s and cannot be used for `enum`s.",
)
)]
pub trait SupportsStaticProperty {}
pub struct CheckSupportsStaticProperty<T: SupportsStaticProperty>(T);
#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
use core::panic::UnwindSafe;
/// Marker trait for types that are UnwindSafe only when building with panic unwind
pub trait MaybeUnwindSafe {}
#[cfg(all(feature = "std", target_arch = "wasm32", panic = "unwind"))]
impl<T: UnwindSafe + ?Sized> MaybeUnwindSafe for T {}
#[cfg(not(all(feature = "std", target_arch = "wasm32", panic = "unwind")))]
impl<T: ?Sized> MaybeUnwindSafe for T {}
/// Private marker trait for erasable generics - types with this trait have the same
/// repr for all generic param values, and can therefore be transmuted on
/// the singular Repr type representation on ABI boundaries.
///
/// # Safety
/// This type must only be implemented on types known to be repr equivalent
/// to their Repr type.
// #[cfg_attr(
// wbg_diagnostic,
// diagnostic::on_unimplemented(
// label = "generic parameter is not a valid Wasm Bindgen ErasableGeneric type",
// note = "\nRecommendation: Add the direct `: wasm_bindgen::JsGeneric` convenience trait bound for JsValue generics, instead of `ErasableGeneric`.\n",
// )
// )]
pub unsafe trait ErasableGeneric {
/// The singular concrete type that all generic variants can be transmuted on
type Repr: 'static;
}
unsafe impl<T: ErasableGeneric> ErasableGeneric for &mut T {
type Repr = &'static mut T::Repr;
}
unsafe impl<T: ErasableGeneric> ErasableGeneric for &T {
type Repr = &'static T::Repr;
}
/// Trait bound marker for types that are passed as an own generic type.
/// Encapsulating the ErasableGeneric invariant that must be maintained, that
/// the repr of the type is the type of the concrete target type repr.
/// This is useful to provide simple debuggable trait bounds for codegen.
#[cfg_attr(
wbg_diagnostic,
diagnostic::on_unimplemented(
message = "Unable to call function, since the concrete generic argument or return value cannot be type-erased into the expected generic repr type for the function",
label = "passed concrete generic type does not match the expected generic repr type",
note = "Make sure that all erasable generic parameters satisfy the trait bound `ErasableGeneric` with the correct repr. Wasm Bindgen generic parameters and return values for functions are defined to work for specific type-erasable generic repr types only.",
)
)]
pub trait ErasableGenericOwn<ConcreteTarget>: ErasableGeneric {}
impl<T, ConcreteTarget> ErasableGenericOwn<ConcreteTarget> for T
where
ConcreteTarget: ErasableGeneric,
T: ErasableGeneric<Repr = <ConcreteTarget as ErasableGeneric>::Repr>,
{
}
/// Trait bound marker for types that are passed as a borrowed generic type.
/// Encapsulating the ErasableGeneric invariant that must be maintained, that
/// the repr of the type is the type of the concrete target type repr.
/// This is useful to provide simple debuggable trait bounds for codegen.
#[cfg_attr(
wbg_diagnostic,
diagnostic::on_unimplemented(
message = "Unable to call this function, since the concrete generic argument or return value cannot be type-erased into the expected generic repr type for the function",
label = "concrete generic type does not match the expected generic repr type",
note = "Make sure that all erasable generic parameters satisfy the trait bound `ErasableGeneric` with the correct repr. Wasm Bindgen generic parameters and return values for functions are defined to work for specific type-erasable generic repr types only.",
)
)]
pub trait ErasableGenericBorrow<Target: ?Sized> {}
impl<'a, T: ?Sized + 'a, ConcreteTarget: ?Sized + 'static> ErasableGenericBorrow<ConcreteTarget>
for T
where
&'static ConcreteTarget: ErasableGeneric,
&'a T: ErasableGeneric<Repr = <&'static ConcreteTarget as ErasableGeneric>::Repr>,
{
}
/// Trait bound marker for types that are passed as a mutable borrowed generic type.
/// Encapsulating the ErasableGeneric invariant that must be maintained, that
/// the repr of the type is the type of the concrete target type repr.
/// This is useful to provide simple debuggable trait bounds for codegen.
#[cfg_attr(
wbg_diagnostic,
diagnostic::on_unimplemented(
message = "Unable to call this function, since the concrete generic argument or return value cannot be type-erased into the expected generic repr type for the function",
label = "concrete generic type does not match the expected generic repr type",
note = "Make sure that all erasable generic parameters satisfy the trait bound `ErasableGeneric` with the correct repr. Wasm Bindgen generic parameters and return values for functions are defined to work for specific type-erasable generic repr types only.",
)
)]
pub trait ErasableGenericBorrowMut<Target: ?Sized> {}
impl<'a, T: ?Sized + 'a, ConcreteTarget: ?Sized + 'static> ErasableGenericBorrowMut<ConcreteTarget>
for T
where
&'static mut ConcreteTarget: ErasableGeneric,
&'a mut T: ErasableGeneric<Repr = <&'static mut ConcreteTarget as ErasableGeneric>::Repr>,
{
}

813
vendor/wasm-bindgen/src/rt/mod.rs vendored Normal file
View File

@@ -0,0 +1,813 @@
use crate::convert::{FromWasmAbi, IntoWasmAbi, WasmAbi, WasmRet};
use crate::describe::inform;
use crate::JsValue;
#[cfg(all(target_arch = "wasm32", feature = "std", panic = "unwind"))]
use core::any::Any;
use core::borrow::{Borrow, BorrowMut};
#[cfg(target_feature = "atomics")]
use core::cell::UnsafeCell;
use core::cell::{Cell, RefCell};
use core::convert::Infallible;
use core::ops::{Deref, DerefMut};
use core::panic::{RefUnwindSafe, UnwindSafe};
#[cfg(target_feature = "atomics")]
use core::sync::atomic::{AtomicU8, Ordering};
use wasm_bindgen_shared::tys::FUNCTION;
use alloc::alloc::{alloc, dealloc, realloc, Layout};
use alloc::rc::Rc;
use once_cell::unsync::Lazy;
pub extern crate alloc;
pub extern crate core;
#[cfg(feature = "std")]
pub extern crate std;
pub mod marker;
pub use wasm_bindgen_macro::BindgenedStruct;
/// Wrapper implementation for JsValue errors, with atomics and std handling
pub fn js_panic(err: JsValue) {
#[cfg(all(feature = "std", not(target_feature = "atomics")))]
::std::panic::panic_any(err);
#[cfg(not(all(feature = "std", not(target_feature = "atomics"))))]
::core::panic!("{:?}", err);
}
// Cast between arbitrary types supported by wasm-bindgen by going via JS.
//
// The implementation generates a no-op JS adapter that simply takes an argument
// in one type, decodes it from the ABI, and then returns the same value back
// encoded with a different type.
pub fn wbg_cast<From: IntoWasmAbi, To: FromWasmAbi>(value: From) -> To {
// Here we need to create a conversion function between arbitrary types
// supported by the wasm-bindgen's ABI.
// 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 is actually a descriptor function, similar to ones we
// generate for imports and exports, except we can't name it here
// because it's generated by monomorphisation for specific types.
// 2. Since we can't name it to associate with a specific import or
// export, we use a different approach. After describing the input
// type, this function internally calls a special import recognized
// by the `wasm-bindgen` CLI tool, `__wbindgen_describe_cast`. This
// imported symbol is similar to `__wbindgen_describe` in that it's
// not intended to show up in the final binary but it's merely a
// signal for `wasm-bindgen` that marks the parent function
// (`breaks_if_inlined`) as a cast descriptor.
//
// 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_cast`. 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 until it reaches the call to
// `__wbindgen_describe_cast`, at which point the interpreter stops.
// * 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 simply
// return the passed in argument, but because it's adapter for our
// descriptors, what we get is actually a general JS cast going via
// Rust input type -> ABI -> JS value -> Rust output type chain.
#[inline(never)]
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
unsafe extern "C" fn breaks_if_inlined<From: IntoWasmAbi, To: FromWasmAbi>(
prim1: <From::Abi as WasmAbi>::Prim1,
prim2: <From::Abi as WasmAbi>::Prim2,
prim3: <From::Abi as WasmAbi>::Prim3,
prim4: <From::Abi as WasmAbi>::Prim4,
) -> WasmRet<To::Abi> {
inform(FUNCTION);
inform(0);
inform(1);
From::describe();
To::describe();
To::describe();
// Pass all inputs and outputs across the opaque FFI boundary to prevent
// compiler from removing them as dead code.
core::ptr::read(super::__wbindgen_describe_cast(
breaks_if_inlined::<From, To> as _,
&(prim1, prim2, prim3, prim4) as *const _ as _,
) as _)
}
let (prim1, prim2, prim3, prim4) = value.into_abi().split();
unsafe { To::from_abi(breaks_if_inlined::<From, To>(prim1, prim2, prim3, prim4).join()) }
}
pub(crate) const JSIDX_OFFSET: u32 = 1024; // keep in sync with js/mod.rs
pub(crate) const JSIDX_UNDEFINED: u32 = JSIDX_OFFSET;
pub(crate) const JSIDX_NULL: u32 = JSIDX_OFFSET + 1;
pub(crate) const JSIDX_TRUE: u32 = JSIDX_OFFSET + 2;
pub(crate) const JSIDX_FALSE: u32 = JSIDX_OFFSET + 3;
pub(crate) const JSIDX_RESERVED: u32 = JSIDX_OFFSET + 4;
pub(crate) struct ThreadLocalWrapper<T>(pub(crate) T);
#[cfg(not(target_feature = "atomics"))]
unsafe impl<T> Sync for ThreadLocalWrapper<T> {}
#[cfg(not(target_feature = "atomics"))]
unsafe impl<T> Send for ThreadLocalWrapper<T> {}
/// Wrapper around [`Lazy`] adding `Send + Sync` when `atomics` is not enabled.
pub struct LazyCell<T, F = fn() -> T>(ThreadLocalWrapper<Lazy<T, F>>);
impl<T, F> LazyCell<T, F> {
pub const fn new(init: F) -> LazyCell<T, F> {
Self(ThreadLocalWrapper(Lazy::new(init)))
}
}
impl<T, F: FnOnce() -> T> LazyCell<T, F> {
pub fn force(this: &Self) -> &T {
&this.0 .0
}
}
impl<T> Deref for LazyCell<T> {
type Target = T;
fn deref(&self) -> &T {
::once_cell::unsync::Lazy::force(&self.0 .0)
}
}
#[cfg(not(target_feature = "atomics"))]
pub use LazyCell as LazyLock;
#[cfg(target_feature = "atomics")]
pub struct LazyLock<T, F = fn() -> T> {
state: AtomicU8,
data: UnsafeCell<Data<T, F>>,
}
#[cfg(target_feature = "atomics")]
enum Data<T, F> {
Value(T),
Init(F),
}
#[cfg(target_feature = "atomics")]
impl<T, F> LazyLock<T, F> {
const STATE_UNINIT: u8 = 0;
const STATE_INITIALIZING: u8 = 1;
const STATE_INIT: u8 = 2;
pub const fn new(init: F) -> LazyLock<T, F> {
Self {
state: AtomicU8::new(Self::STATE_UNINIT),
data: UnsafeCell::new(Data::Init(init)),
}
}
}
#[cfg(target_feature = "atomics")]
impl<T> Deref for LazyLock<T> {
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!(),
}
}
}
}
#[cfg(target_feature = "atomics")]
unsafe impl<T, F: Sync> Sync for LazyLock<T, F> {}
#[cfg(target_feature = "atomics")]
unsafe impl<T, F: Send> Send for LazyLock<T, F> {}
#[macro_export]
#[doc(hidden)]
#[cfg(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(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<T>(s: *mut T) {
if s.is_null() {
throw_null();
}
}
#[cold]
#[inline(never)]
fn throw_null() -> ! {
super::throw_str("null pointer passed to rust");
}
/// A wrapper around the `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<T: ?Sized> {
inner: RefCell<T>,
}
impl<T: ?Sized> UnwindSafe for WasmRefCell<T> {}
impl<T: ?Sized> RefUnwindSafe for WasmRefCell<T> {}
impl<T: ?Sized> WasmRefCell<T> {
pub fn new(value: T) -> WasmRefCell<T>
where
T: Sized,
{
WasmRefCell {
inner: RefCell::new(value),
}
}
pub fn get_mut(&mut self) -> &mut T {
self.inner.get_mut()
}
pub fn borrow(&self) -> Ref<'_, T> {
match self.inner.try_borrow() {
Ok(inner) => Ref { inner },
Err(_) => borrow_fail(),
}
}
pub fn borrow_mut(&self) -> RefMut<'_, T> {
match self.inner.try_borrow_mut() {
Ok(inner) => RefMut { inner },
Err(_) => borrow_fail(),
}
}
pub fn into_inner(self) -> T
where
T: Sized,
{
self.inner.into_inner()
}
}
pub struct Ref<'b, T: ?Sized + 'b> {
inner: core::cell::Ref<'b, T>,
}
impl<T: ?Sized> Deref for Ref<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner
}
}
impl<T: ?Sized> Borrow<T> for Ref<'_, T> {
#[inline]
fn borrow(&self) -> &T {
self
}
}
pub struct RefMut<'b, T: ?Sized + 'b> {
inner: core::cell::RefMut<'b, T>,
}
impl<T: ?Sized> Deref for RefMut<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner
}
}
impl<T: ?Sized> DerefMut for RefMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}
impl<T: ?Sized> Borrow<T> for RefMut<'_, T> {
#[inline]
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized> BorrowMut<T> for RefMut<'_, T> {
#[inline]
fn borrow_mut(&mut self) -> &mut T {
self
}
}
#[cfg(panic = "unwind")]
fn borrow_fail() -> ! {
panic!(
"recursive use of an object detected which would lead to \
unsafe aliasing in rust",
)
}
#[cfg(not(panic = "unwind"))]
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<WasmRefCell<T>>` 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<T: ?Sized + 'static> {
// 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<WasmRefCell<T>>,
}
impl<T: ?Sized> UnwindSafe for RcRef<T> {}
impl<T: ?Sized> RcRef<T> {
pub fn new(rc: Rc<WasmRefCell<T>>) -> Self {
let ref_ = unsafe { (*Rc::as_ptr(&rc)).borrow() };
Self { _rc: rc, ref_ }
}
}
impl<T: ?Sized> Deref for RcRef<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.ref_
}
}
impl<T: ?Sized> Borrow<T> for RcRef<T> {
#[inline]
fn borrow(&self) -> &T {
&self.ref_
}
}
/// A type that encapsulates an `Rc<WasmRefCell<T>>` 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<T: ?Sized + 'static> {
ref_: RefMut<'static, T>,
_rc: Rc<WasmRefCell<T>>,
}
impl<T: ?Sized> RcRefMut<T> {
pub fn new(rc: Rc<WasmRefCell<T>>) -> Self {
let ref_ = unsafe { (*Rc::as_ptr(&rc)).borrow_mut() };
Self { _rc: rc, ref_ }
}
}
impl<T: ?Sized> Deref for RcRefMut<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.ref_
}
}
impl<T: ?Sized> DerefMut for RcRefMut<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.ref_
}
}
impl<T: ?Sized> Borrow<T> for RcRefMut<T> {
#[inline]
fn borrow(&self) -> &T {
&self.ref_
}
}
impl<T: ?Sized> BorrowMut<T> for RcRefMut<T> {
#[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_attr(target_feature = "atomics", thread_local)]
static GLOBAL_EXNDATA: ThreadLocalWrapper<Cell<[u32; 2]>> = ThreadLocalWrapper(Cell::new([0; 2]));
#[cfg(panic = "unwind")]
#[no_mangle]
pub static mut __instance_terminated: u32 = 0;
#[no_mangle]
pub unsafe extern "C" fn __wbindgen_exn_store(idx: u32) {
debug_assert_eq!(GLOBAL_EXNDATA.0.get()[0], 0);
GLOBAL_EXNDATA.0.set([1, idx]);
}
pub fn take_last_exception() -> Result<(), super::JsValue> {
let ret = if GLOBAL_EXNDATA.0.get()[0] == 1 {
Err(super::JsValue::_new(GLOBAL_EXNDATA.0.get()[1]))
} else {
Ok(())
};
GLOBAL_EXNDATA.0.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<JsValue, JsValue>` which is what we'll return to JS (where an
/// error is a failed future).
pub trait IntoJsResult {
fn into_js_result(self) -> Result<JsValue, JsValue>;
}
impl IntoJsResult for () {
fn into_js_result(self) -> Result<JsValue, JsValue> {
Ok(JsValue::undefined())
}
}
impl<T: Into<JsValue>> IntoJsResult for T {
fn into_js_result(self) -> Result<JsValue, JsValue> {
Ok(self.into())
}
}
impl<T: Into<JsValue>, E: Into<JsValue>> IntoJsResult for Result<T, E> {
fn into_js_result(self) -> Result<JsValue, JsValue> {
match self {
Ok(e) => Ok(e.into()),
Err(e) => Err(e.into()),
}
}
}
impl<E: Into<JsValue>> IntoJsResult for Result<(), E> {
fn into_js_result(self) -> Result<JsValue, JsValue> {
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<E: Into<JsValue>> 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<T>(pub Option<T>);
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<Infallible> {
#[inline]
fn __wasm_bindgen_main(&mut self) {}
}
impl<E: Into<JsValue>> Main for &mut &mut MainWrapper<Result<(), E>> {
#[inline]
fn __wasm_bindgen_main(&mut self) {
if let Err(e) = self.0.take().unwrap() {
crate::throw_val(e.into());
}
}
}
impl<E: core::fmt::Debug> Main for &mut MainWrapper<Result<(), E>> {
#[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<T, const SIZE: usize>(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<const RESULT_LEN: usize, const SIZE: usize>(
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
}
#[cfg(all(target_arch = "wasm32", feature = "std", panic = "unwind"))]
#[wasm_bindgen_macro::wasm_bindgen(wasm_bindgen = crate, raw_module = "__wbindgen_placeholder__")]
extern "C" {
fn __wbindgen_panic_error(msg: &JsValue) -> JsValue;
}
#[cfg(all(target_arch = "wasm32", feature = "std", panic = "unwind"))]
pub fn panic_to_panic_error(val: std::boxed::Box<dyn Any + Send>) -> JsValue {
#[cfg(not(target_feature = "atomics"))]
{
if let Some(s) = val.downcast_ref::<JsValue>() {
return __wbindgen_panic_error(&s);
}
}
let maybe_panic_msg: Option<&str> = if let Some(s) = val.downcast_ref::<&str>() {
Some(s)
} else if let Some(s) = val.downcast_ref::<std::string::String>() {
Some(s)
} else {
None
};
let err: JsValue = __wbindgen_panic_error(&JsValue::from_str(
maybe_panic_msg.unwrap_or("No panic message available"),
));
err
}
#[cfg(all(target_arch = "wasm32", feature = "std", panic = "unwind"))]
pub fn maybe_catch_unwind<F: FnOnce() -> R + std::panic::UnwindSafe, R>(f: F) -> R {
let result = std::panic::catch_unwind(f);
match result {
Ok(val) => val,
Err(e) => {
crate::throw_val(panic_to_panic_error(e));
}
}
}
#[cfg(not(all(target_arch = "wasm32", feature = "std", panic = "unwind")))]
pub fn maybe_catch_unwind<F: FnOnce() -> R, R>(f: F) -> R {
f()
}

272
vendor/wasm-bindgen/src/sys.rs vendored Normal file
View File

@@ -0,0 +1,272 @@
//! JavaScript system types that are re-exported by `js-sys`.
//!
//! These types represent fundamental JavaScript values and are designed to be
//! used as generic type parameters in typed JavaScript collections and APIs.
use crate::convert::UpcastFrom;
use crate::JsCast;
use crate::JsGeneric;
use crate::JsValue;
use core::fmt;
use core::mem::ManuallyDrop;
use core::ops::Deref;
use wasm_bindgen_macro::wasm_bindgen;
/// Marker trait for types which represent `Resolution` or `Promise<Resolution>`.
///
/// For all types except for `Promise`, `Resolution` is equal to the type itself.
/// For `Promise` or any thenable or type extending Promise, `Resolution` is the
/// type of the promise resolution.
///
/// Manually implementing this trait is only required for custom thenables or
/// types which extend Promise. To disable automatic implementation, use the
/// `#[wasm_bindgen(no_promising)]` attribute.
pub trait Promising {
/// The type that this value resolves to.
type Resolution;
}
// Undefined
#[wasm_bindgen(wasm_bindgen = crate)]
extern "C" {
/// The JavaScript `undefined` value.
///
/// This type represents the JavaScript `undefined` primitive value and can be
/// used as a generic type parameter to indicate that a value is `undefined`.
#[wasm_bindgen(is_type_of = JsValue::is_undefined, typescript_type = "undefined", no_upcast)]
#[derive(Clone, PartialEq)]
pub type Undefined;
}
impl Undefined {
/// The undefined constant.
pub const UNDEFINED: Undefined = Self {
obj: JsValue::UNDEFINED,
};
}
impl Eq for Undefined {}
impl Default for Undefined {
fn default() -> Self {
Self::UNDEFINED
}
}
impl fmt::Debug for Undefined {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("undefined")
}
}
impl fmt::Display for Undefined {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("undefined")
}
}
impl UpcastFrom<Undefined> for Undefined {}
impl UpcastFrom<()> for Undefined {}
impl UpcastFrom<Undefined> for () {}
impl UpcastFrom<Undefined> for JsValue {}
// Null
#[wasm_bindgen(wasm_bindgen = crate)]
extern "C" {
/// The JavaScript `null` value.
///
/// This type represents the JavaScript `null` primitive value and can be
/// used as a generic type parameter to indicate that a value is `null`.
#[wasm_bindgen(is_type_of = JsValue::is_null, typescript_type = "null", no_upcast)]
#[derive(Clone, PartialEq)]
pub type Null;
}
impl Null {
/// The null constant.
pub const NULL: Null = Self { obj: JsValue::NULL };
}
impl Eq for Null {}
impl Default for Null {
fn default() -> Self {
Self::NULL
}
}
impl fmt::Debug for Null {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("null")
}
}
impl fmt::Display for Null {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("null")
}
}
impl UpcastFrom<Null> for Null {}
impl UpcastFrom<Null> for JsValue {}
// JsOption
#[wasm_bindgen(wasm_bindgen = crate)]
extern "C" {
/// A nullable JS value of type `T`.
///
/// Unlike `Option<T>`, which is a Rust-side construct, `JsOption<T>` represents
/// a JS value that may be `T`, `null`, or `undefined`, where the null status is
/// not yet known in Rust. The value remains in JS until inspected via methods
/// like [`is_empty`](Self::is_empty), [`as_option`](Self::as_option), or
/// [`into_option`](Self::into_option).
///
/// `T` must implement [`JsGeneric`], meaning it is any type that can be
/// represented as a `JsValue` (e.g., `JsString`, `Number`, `Object`, etc.).
/// `JsOption<T>` itself implements `JsGeneric`, so it can be used in all
/// generic positions that accept JS types.
#[wasm_bindgen(typescript_type = "any", no_upcast)]
#[derive(Clone, PartialEq)]
pub type JsOption<T>;
}
impl<T> JsOption<T> {
/// Creates an empty `JsOption<T>` representing `null`.
#[inline]
pub fn new() -> Self {
Null::NULL.unchecked_into()
}
/// Wraps a value in a `JsOption<T>`.
#[inline]
pub fn wrap(val: T) -> Self {
unsafe { core::mem::transmute_copy(&ManuallyDrop::new(val)) }
}
/// Creates a `JsOption<T>` from an `Option<T>`.
///
/// Returns `JsOption::wrap(val)` if `Some(val)`, otherwise `JsOption::new()`.
#[inline]
pub fn from_option(opt: Option<T>) -> Self {
match opt {
Some(val) => Self::wrap(val),
None => Self::new(),
}
}
/// Tests whether this `JsOption<T>` is empty (`null` or `undefined`).
#[inline]
pub fn is_empty(&self) -> bool {
JsValue::is_null_or_undefined(self)
}
/// Converts this `JsOption<T>` to an `Option<T>` by cloning the inner value.
///
/// Returns `None` if the value is `null` or `undefined`, otherwise returns
/// `Some(T)` with a clone of the contained value.
#[inline]
pub fn as_option(&self) -> Option<T> {
if JsValue::is_null_or_undefined(self) {
None
} else {
let cloned = self.deref().clone();
Some(unsafe { core::mem::transmute_copy(&ManuallyDrop::new(cloned)) })
}
}
/// Converts this `JsOption<T>` into an `Option<T>`, consuming `self`.
///
/// Returns `None` if the value is `null` or `undefined`, otherwise returns
/// `Some(T)` with the contained value.
#[inline]
pub fn into_option(self) -> Option<T> {
if JsValue::is_null_or_undefined(&self) {
None
} else {
Some(unsafe { core::mem::transmute_copy(&ManuallyDrop::new(self)) })
}
}
/// Returns the contained value, consuming `self`.
///
/// # Panics
///
/// Panics if the value is `null` or `undefined`.
#[inline]
pub fn unwrap(self) -> T {
self.expect("called `JsOption::unwrap()` on an empty value")
}
/// Returns the contained value, consuming `self`.
///
/// # Panics
///
/// Panics if the value is `null` or `undefined`, with a panic message
/// including the passed message.
#[inline]
pub fn expect(self, msg: &str) -> T {
match self.into_option() {
Some(val) => val,
None => panic!("{}", msg),
}
}
/// Returns the contained value or a default.
///
/// Returns the contained value if not `null` or `undefined`, otherwise
/// returns the default value of `T`.
#[inline]
pub fn unwrap_or_default(self) -> T
where
T: Default,
{
self.into_option().unwrap_or_default()
}
/// Returns the contained value or computes it from a closure.
///
/// Returns the contained value if not `null` or `undefined`, otherwise
/// calls `f` and returns the result.
#[inline]
pub fn unwrap_or_else<F>(self, f: F) -> T
where
F: FnOnce() -> T,
{
self.into_option().unwrap_or_else(f)
}
}
impl<T: JsGeneric> Default for JsOption<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: JsGeneric + fmt::Debug> fmt::Debug for JsOption<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}?(", core::any::type_name::<T>())?;
match self.as_option() {
Some(v) => write!(f, "{v:?}")?,
None => f.write_str("null")?,
}
f.write_str(")")
}
}
impl<T: JsGeneric + fmt::Display> fmt::Display for JsOption<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}?(", core::any::type_name::<T>())?;
match self.as_option() {
Some(v) => write!(f, "{v}")?,
None => f.write_str("null")?,
}
f.write_str(")")
}
}
impl UpcastFrom<JsValue> for JsOption<JsValue> {}
impl<T> UpcastFrom<Undefined> for JsOption<T> {}
impl<T> UpcastFrom<Null> for JsOption<T> {}
impl<T> UpcastFrom<()> for JsOption<T> {}
impl<T> UpcastFrom<JsOption<T>> for JsValue {}
impl<T, U> UpcastFrom<JsOption<U>> for JsOption<T> where T: UpcastFrom<U> {}