Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
@@ -0,0 +1 @@
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"cb3e014e8ed6b750351c01a7eb103fab983367b7d20917bb058d7e7b1f1b71c5","Cargo.lock":"e5139a4ddb1d617edd49aa23d915af008409f81f9f246a296aca35e0a08d9923","Cargo.toml":"97f2a3cf67d36d1f94880de0d1ca70063e81a5d977cc6289b34c222a4f715ba6","Cargo.toml.orig":"3e18862ec9ff0cf81583cf74fff44596a36a63e5a3a71cc048ee87a18a7b8fc0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"006f14ae5ec54943737bddd9342eb24975a0e95b808f76d4c98258d3fea75d2d","build.rs":"33c90a6eb1745c53f9047e0ecde135b249b0ea3d9e1a2a40c9610a33f225e6c9","src/cache/intern.rs":"b354990c27d418b201a918782f1aa736c2cafd31fcde694bb19aa58c5bc47449","src/cache/mod.rs":"8989143b55160dbc142cb20c6e066cf0a3f70d6c97fbc9aa0fac59bd62bd865b","src/cast.rs":"156a9b71bf9af03c5c378a1939032dfc628edbefce4aa8c37fb14948abf7a9f4","src/closure.rs":"d3a2e285b7c582c970594dfd9edd9ee822c7c9b86ee8b236497b296c441ef5b7","src/convert/closures.rs":"f1004f4a022f4d063414bc67720fbb04327955c02837241b37fb8298f5fd345e","src/convert/impls.rs":"5d4e3bfaf2e4a3152b8a1b0b2883ee3658317e3f70aa3426d3625dfadcb1b007","src/convert/mod.rs":"a284115f8080ee36ea60d6a111d4247856bdee76c4a5b738465f60a97c593eca","src/convert/slices.rs":"3d6ac72ff8e49c10d77878cc79678ce48f12af0d23cf753e3f76a1092c2cb2bb","src/convert/traits.rs":"2fa56c946544eb6b09e16977ee6efbcf11d5af35039a21041095ff83b9621cdb","src/describe.rs":"fe9fbef496f7908156a522d781f813cfc258e39ecdc15c40ba666a4ef24ea624","src/externref.rs":"40d3a6011ff7341c9b1a4bcecc7ddc459f8bf9e7ba37e6a523bcfc66a3ba87d3","src/handler.rs":"fd187aadf360c2d13e9153fd58a5b640b656dfa892e9bdbe726f96b0636a7f09","src/lib.rs":"b41c47675d6cc4c1ef423341b6b28b932ddf11bdff477f191129305c2cafc972","src/link.rs":"96fdb40e29ffae7b9621d78eec24437bdc6db2473f6d2f8eff1f987d2b566852","src/parent.rs":"d9f90c6eaa6bf00cae48858305eff077947e6558f02da493033f4e4fc09ac7ce","src/rt/marker.rs":"145fbe1e446b18abe405b8fc4a87ec2b3fea17dd9e48491d1d698f08f5e0e3bb","src/rt/mod.rs":"17fc0f950d8800a9aa5979fe84be213019385e9b17e5a7e17c2fb702777cdb56","src/sys.rs":"7450229d24b97ca80f9880c1413437644b82ca1141627ef959b39d8a652cb380"},"package":"4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"}
@@ -0,0 +1,6 @@
{
"git": {
"sha1": "21ac804a96c0c5c5d6459084686a9a17a8a3c865"
},
"path_in_vcs": ""
}
+175
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.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[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.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "memchr"
version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[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.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
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.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]]
name = "syn"
version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
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.126"
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.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
dependencies = [
"bumpalo",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
dependencies = [
"unicode-ident",
]
[[package]]
name = "zmij"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+122
View File
@@ -0,0 +1,122 @@
# 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.77"
name = "wasm-bindgen"
version = "0.2.126"
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.126"
[dependencies.wasm-bindgen-shared]
version = "=0.2.126"
[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"
[target.'cfg(target_arch = "wasm64")'.dev-dependencies.paste]
version = "1"
[target.'cfg(target_arch = "wasm64")'.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(wasm_bindgen_use_js_sys)",
"cfg(xxx_debug_only_print_generated_code)",
"cfg(legacy_eh)",
]
+151
View File
@@ -0,0 +1,151 @@
[package]
authors = ["The wasm-bindgen Developers"]
categories = ["wasm"]
description = """
Easy support for interacting between JS and Rust.
"""
documentation = "https://docs.rs/wasm-bindgen"
edition = "2021"
homepage = "https://wasm-bindgen.github.io/wasm-bindgen"
include = ["/build.rs", "/LICENSE-*", "/src"]
license = "MIT OR Apache-2.0"
name = "wasm-bindgen"
readme = "README.md"
repository = "https://github.com/wasm-bindgen/wasm-bindgen"
rust-version = "1.77"
version = "0.2.126"
[package.metadata.docs.rs]
features = ["serde-serialize"]
[lib]
test = false
[features]
default = ["std"]
enable-interning = ["std"]
serde-serialize = ["serde", "serde_json", "std"]
spans = []
std = []
# Whether or not the `#[wasm_bindgen]` macro is strict and generates an error on
# all unused attributes
strict-macro = ["wasm-bindgen-macro/strict-macro"]
# INTERNAL ONLY: Enables gg-alloc as system allocator when using wasm-bindgen-test to check that large pointers
# are handled correctly
gg-alloc = ["wasm-bindgen-test/gg-alloc"]
# Deprecated crate features
msrv = []
rustversion = []
xxx_debug_only_print_generated_code = []
[dependencies]
cfg-if = "1.0.0"
once_cell = { version = "1.12", default-features = false }
serde = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.126" }
wasm-bindgen-shared = { path = "crates/shared", version = "=0.2.126" }
[build-dependencies]
# In older MSRVs, dependencies and crate features can't have the same name.
rustversion-compat = { package = "rustversion", version = "1.0.6" }
[dev-dependencies]
once_cell = "1"
wasm-bindgen-test = { path = 'crates/test' }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
js-sys = { path = 'crates/js-sys', features = ["unsafe-eval"] }
paste = "1"
serde_derive = "1.0"
wasm-bindgen-futures = { path = 'crates/futures' }
wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
wasm-bindgen-test-crate-b = { path = 'tests/crates/b' }
[target.'cfg(target_arch = "wasm64")'.dev-dependencies]
js-sys = { path = 'crates/js-sys', features = ["unsafe-eval"] }
paste = "1"
serde_derive = "1.0"
wasm-bindgen-futures = { path = 'crates/futures' }
wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
wasm-bindgen-test-crate-b = { path = 'tests/crates/b' }
[lints]
workspace = true
[workspace.lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(wasm_bindgen_unstable_test_coverage)',
'cfg(wasm_bindgen_use_js_sys)',
'cfg(xxx_debug_only_print_generated_code)',
'cfg(legacy_eh)',
] }
unused_lifetimes = "warn"
[workspace.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"
[workspace]
exclude = ["crates/msrv/resolver", "crates/msrv/lib", "crates/msrv/cli"]
members = [
"benchmarks",
"benchmarks/wcodspeed",
"crates/cli",
"crates/js-sys",
"crates/test",
"crates/test/sample",
"crates/typescript-tests",
"crates/web-sys",
"crates/webidl",
"crates/webidl-tests",
"examples/add",
"examples/canvas",
"examples/char",
"examples/closures",
"examples/console_log",
"examples/nodejs_and_deno",
"examples/nodejs-threads",
"examples/dom",
"examples/duck-typed-interfaces",
"examples/explicit-resource-management",
"examples/fetch",
"examples/guide-supported-types-examples",
"examples/hello_world",
"examples/import_js/crate",
"examples/julia_set",
"examples/paint",
"examples/performance",
"examples/raytrace-parallel",
"examples/request-animation-frame",
"examples/todomvc",
"examples/wasm-audio-worklet",
"examples/wasm-in-wasm",
"examples/wasm-in-wasm-imports",
"examples/wasm-in-web-worker",
"examples/weather_report",
"examples/webaudio",
"examples/webgl",
"examples/webrtc_datachannel",
"examples/websockets",
"examples/webxr",
"examples/without-a-bundler",
"examples/without-a-bundler-no-modules",
"examples/synchronous-instantiation",
"tests/no-std",
]
resolver = "2"
[patch.crates-io]
js-sys = { path = 'crates/js-sys' }
wasm-bindgen = { path = '.' }
wasm-bindgen-futures = { path = 'crates/futures' }
wasm-bindgen-test = { path = 'crates/test' }
web-sys = { path = 'crates/web-sys' }
+201
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
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.
+143
View File
@@ -0,0 +1,143 @@
<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/main/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.77.
* CLI tools and their corresponding support libraries have a MSRV of v1.86.
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.118 | 1.77 | 1.86 | 2026-04-10 |
| 0.2.106 | 1.71 | 1.82 | 2025-11-27 |
| 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
+49
View File
@@ -0,0 +1,49 @@
// 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_arch == "wasm64")
&& target_os == "unknown"
&& rustversion::cfg!(all(since(1.82), before(1.84))))
{
println!("cargo:rustc-cfg=wbg_reference_types");
}
if target_arch == "wasm32" && target_os == "emscripten" {
// Emscripten uses emcc to handle the linking and it will deadcode elimainte __instance_terminated
// which causes the test on Emscripten to fail to build.
println!("cargo:rustc-link-arg=-Wl,--export=__instance_terminated");
}
}
+103
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
View File
@@ -0,0 +1 @@
pub mod intern;
+172
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()
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,506 @@
use alloc::boxed::Box;
use core::mem;
use core::panic::AssertUnwindSafe;
use crate::__rt::marker::ErasableGeneric;
use crate::__rt::maybe_catch_unwind;
use crate::__rt::WasmWord;
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::from_usize(a, b)
}
}
}
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: WasmWord,
b: WasmWord,
$(
$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.is_zero() {
throw_str("closure invoked recursively or after being dropped");
}
let ret = {
let f: & $($mut)? dyn $Fn $FnArgs -> R =
mem::transmute((a.into_usize(), b.into_usize()));
$(
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>,
{
}
+856
View File
@@ -0,0 +1,856 @@
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::__rt::{WasmSignedWordRepr, WasmWordRepr};
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> {}
/// Sentinel value used to encode `None` for optional pointer-sized and
/// 32-bit numeric values transferred over the JS `number` ABI.
///
/// `2^53 - 1` (`Number.MAX_SAFE_INTEGER`) is chosen because it is:
/// - exactly representable as an `f64` (so JS round-trips it losslessly),
/// - outside the range of any valid `i32`/`u32`/`f32` value (so it can't
/// collide with a real `Some(...)` payload from those types), and
/// - far above any plausible wasm64 pointer (which is bounded by the
/// memory-64 address space limit, well below `2^53`).
const F64_ABI_OPTION_SENTINEL: f64 = 9007199254740991_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
u32 as u32
f32 as f32
isize as WasmSignedWordRepr
usize as WasmWordRepr
);
#[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 = WasmWordRepr;
#[inline]
fn into_abi(self) -> Self::Abi {
self as usize as WasmWordRepr
}
}
impl<T> FromWasmAbi for *const T {
type Abi = WasmWordRepr;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> *const T {
js as usize 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) -> Self::Abi {
self.map(|ptr| ptr as usize 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: Self::Abi) -> Option<*const T> {
if js == F64_ABI_OPTION_SENTINEL {
None
} else {
Some(js as usize as *const T)
}
}
}
impl<T> IntoWasmAbi for *mut T {
type Abi = WasmWordRepr;
#[inline]
fn into_abi(self) -> Self::Abi {
self as usize as WasmWordRepr
}
}
impl<T> FromWasmAbi for *mut T {
type Abi = WasmWordRepr;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> *mut T {
js as usize as *mut T
}
}
impl<T> IntoWasmAbi for Option<*mut T> {
type Abi = f64;
#[inline]
fn into_abi(self) -> Self::Abi {
self.map(|ptr| ptr as usize as f64)
.unwrap_or(F64_ABI_OPTION_SENTINEL)
}
}
impl<T> FromWasmAbi for Option<*mut T> {
type Abi = f64;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Option<*mut T> {
if js == F64_ABI_OPTION_SENTINEL {
None
} else {
Some(js as usize as *mut T)
}
}
}
impl<T> IntoWasmAbi for NonNull<T> {
type Abi = WasmWordRepr;
#[inline]
fn into_abi(self) -> Self::Abi {
self.as_ptr() as usize as WasmWordRepr
}
}
impl<T> OptionIntoWasmAbi for NonNull<T> {
#[inline]
fn none() -> Self::Abi {
0 as WasmWordRepr
}
}
impl<T> FromWasmAbi for NonNull<T> {
type Abi = WasmWordRepr;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
// SAFETY: Checked in bindings.
NonNull::new_unchecked(js as usize as *mut T)
}
}
impl<T> OptionFromWasmAbi for NonNull<T> {
#[inline]
fn is_none(js: &Self::Abi) -> bool {
*js == 0 as WasmWordRepr
}
}
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()
}
}
// `JsError` is `#[repr(transparent)]` over `JsValue`
impl FromWasmAbi for JsError {
type Abi = <JsValue as FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
JsError {
value: JsValue::from_abi(js),
}
}
}
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
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::{VectorRefIntoWasmAbi, WasmSlice};
pub use self::traits::*;
+581
View File
@@ -0,0 +1,581 @@
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, WasmWord};
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: WasmWord,
pub len: WasmWord,
}
impl WasmSlice {
#[inline]
pub fn from_usize(ptr: usize, len: usize) -> Self {
Self {
ptr: WasmWord::from_usize(ptr),
len: WasmWord::from_usize(len),
}
}
}
impl WasmAbi for WasmSlice {
/// `self.ptr`
type Prim1 = <WasmWord as WasmAbi>::Prim1;
/// `self.len`
type Prim2 = <WasmWord as WasmAbi>::Prim1;
type Prim3 = ();
type Prim4 = ();
#[inline]
fn split(self) -> (Self::Prim1, Self::Prim2, (), ()) {
(self.ptr.split().0, self.len.split().0, (), ())
}
#[inline]
fn join(ptr: Self::Prim1, len: Self::Prim2, _: (), _: ()) -> Self {
Self {
ptr: WasmWord::join(ptr, (), (), ()),
len: WasmWord::join(len, (), (), ()),
}
}
}
#[inline]
fn null_slice() -> WasmSlice {
WasmSlice::from_usize(0, 0)
}
pub struct WasmMutSlice {
pub slice: WasmSlice,
pub idx: u32,
}
impl WasmAbi for WasmMutSlice {
/// `self.slice.ptr`
type Prim1 = <WasmSlice as WasmAbi>::Prim1;
/// `self.slice.len`
type Prim2 = <WasmSlice as WasmAbi>::Prim2;
/// `self.idx`
type Prim3 = u32;
type Prim4 = ();
#[inline]
fn split(self) -> (Self::Prim1, Self::Prim2, u32, ()) {
let (ptr, len, (), ()) = self.slice.split();
(ptr, len, self.idx, ())
}
#[inline]
fn join(ptr: Self::Prim1, len: Self::Prim2, idx: u32, _: ()) -> Self {
Self {
slice: WasmSlice::join(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::from_usize(ptr as usize, len)
}
}
impl VectorFromWasmAbi for $t {
type Abi = WasmSlice;
#[inline]
unsafe fn vector_from_abi(js: WasmSlice) -> Box<[$t]> {
let ptr = js.ptr.into_usize() as *mut $t;
let len = js.len.into_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::from_usize(self.as_ptr() as usize, self.len())
}
}
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::from_usize(0, x as usize))
}
} 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()
}
}
/// Internal trait used by the `slice_to_array` macro codegen.
///
/// Produces the wire representation JS observes when an outgoing `&[T]`
/// argument is rendered as a plain `Array`. There are two impl shapes,
/// neither of which requires `T: Clone`:
///
/// * For primitive numeric `T` (`u8`, `i32`, `f64`, ...) the wire is a
/// borrow of the slice memory directly — no allocation, no copy. The
/// JS-side shim performs `Array.from(typedArrayView)` to materialise
/// the JS `Array` and never frees the buffer.
/// * For everything else (`String`, `JsValue`, imported types, exported
/// types) the wire is a freshly allocated `Box<[u32]>` of externref
/// indices — one per element, constructed via `&T -> JsValue` (which
/// for handle-shaped types is a refcount bump on the existing JS
/// slot, and for `String` / value-shaped types creates a fresh JS
/// value). The JS-side shim reads the indices into a JS `Array` and
/// frees the index buffer.
///
/// Both shapes carry the same `WasmSlice` (ptr + len) on the wire. The
/// cli-support side picks the right JS shim based on the element
/// `VectorKind` recovered from the descriptor.
///
/// Not user-facing: users opt in via `#[wasm_bindgen(slice_to_array)]`
/// on an imported function or `extern "C"` block.
pub trait VectorRefIntoWasmAbi {
/// Construct the wire representation for `Some(slice)`. The returned
/// `WasmSlice` is either a borrow of the input slice (primitive
/// case) or a buffer JS owns and frees (handle-shaped case).
fn slice_into_abi(slice: &[Self]) -> WasmSlice
where
Self: Sized;
/// Wire representation for `None` (used by `Option<&[T]>`). A null
/// `WasmSlice` (`ptr == 0`) is the convention shared with every
/// other vector-like ABI in the crate.
#[inline]
fn slice_none() -> WasmSlice
where
Self: Sized,
{
null_slice()
}
}
macro_rules! vector_ref_into_wasm_abi_primitive {
($($t:ty)*) => ($(
impl VectorRefIntoWasmAbi for $t {
#[inline]
fn slice_into_abi(slice: &[Self]) -> WasmSlice {
// Borrow of the slice memory; the JS shim does
// `Array.from(view)` and never frees.
WasmSlice::from_usize(slice.as_ptr() as usize, slice.len())
}
}
)*);
}
vector_ref_into_wasm_abi_primitive!(u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64);
impl<T> VectorRefIntoWasmAbi for T
where
for<'a> &'a T: Into<JsValue>,
{
#[inline]
fn slice_into_abi(slice: &[Self]) -> WasmSlice {
// Build a fresh `[JsValue]` buffer one element at a time. The
// existing `Vec<JsValue>` ABI hands off the buffer to JS; the
// JS shim drops each externref slot it reads and frees the
// buffer.
let js_vals: Box<[JsValue]> = slice.iter().map(Into::into).collect();
js_vals.into_abi()
}
}
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.is_zero()
}
}
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.is_zero()
}
}
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.is_zero()
}
}
impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> VectorFromWasmAbi for T {
type Abi = WasmSlice;
#[inline]
unsafe fn vector_from_abi(js: WasmSlice) -> Box<[Self]> {
let ptr = js.ptr.into_usize() as *mut T;
let len = js.len.into_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::from_usize(ptr as usize, len)
}
}
// 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::from_usize(self.as_ptr() as usize, self.len())
}
}
impl<T: ErasableGeneric<Repr = JsValue> + WasmDescribe> OptionIntoWasmAbi for &[T] {
#[inline]
fn none() -> WasmSlice {
null_slice()
}
}
+640
View File
@@ -0,0 +1,640 @@
use core::borrow::Borrow;
use core::ops::{Deref, DerefMut};
use core::panic::AssertUnwindSafe;
use crate::sys::JsOption;
use crate::{describe::*, JsCast};
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.
//
// &mut T references are invariant. If you accept &mut T, you cannot upcast it
// and write back a different type the caller could see.
// Eg. this is not valid:
// ```ignore
// let mut string = JsString::from("valid");
// let string_ref: &mut JsString = &mut string;
// // If &mut T was modeled as just covariant, we could upcast this to
// // &mut JsValue.
// let js_value_ref: &mut JsValue = string_ref.upcast_into();
// *js_value_ref = Object::new().into();
// // string is still typed as JsString, but it now wraps a plain object.
// // Converting it to a Rust String throws because the value is not a string.
// let _ = String::from(&string);
// ```
//
// Requiring `UpcastFrom` in *both* directions means `T` and `Target` have to be
// mutually upcastable -- i.e. equivalent, with the same set of valid values.
// That is exactly what makes a `&mut` cast sound: anything written back through
// the wider `&mut Target` view is still a valid `T`. So this rejects every
// widening (the `JsString` -> `JsValue` case above, where `JsValue` does not
// upcast back to `JsString`), while still allowing casts between genuinely
// equivalent types in either direction. For example `()` and `Undefined` both
// model "nothing" and upcast to each other, so a
// `&mut Closure<dyn Fn(Undefined)>` can be upcast to a `&mut Closure<dyn Fn(())>`
// and back.
impl<'a, T: ?Sized, Target: ?Sized> UpcastFrom<&'a mut T> for &'a mut Target
where
Target: UpcastFrom<T>,
T: UpcastFrom<Target>,
{
}
// &T references are covariant, so we can allow from a specific type to a more general type
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>
+ JsCast
+ 'static
{
}
impl<T: ErasableGeneric<Repr = JsValue> + UpcastFrom<T> + Upcast<JsValue> + JsCast + 'static>
JsGeneric for T
{
}
/// Value conversion from a type into its canonical [`JsGeneric`] form.
///
/// This trait allows types to be converted into JsGeneric supported types, which
/// are required to be erasably generic with JsValue.
///
/// The single associated type — rather than a free type parameter bounded by
/// `AsRef<T>` — is what makes collection-style APIs infer annotation-free.
/// Given an input `A`, there is exactly one `A::JsCanon`, so rustc never has
/// to search across multiple `AsRef` impls to pick a target element type.
///
/// # Implementations
///
/// Provided impls:
/// - [`JsValue`] in this crate.
/// - Every `#[wasm_bindgen]`-imported type (identity — emitted by the macro).
/// - Every generic `js_sys` container (`Array<T>`, `Promise<T>`, `Set<T>`, …)
/// provides its own identity impl owned by `js_sys`.
/// - References to cloneable implementors, so borrowed iteration can still
/// produce owned JS-generic values.
///
/// This trait is deliberately *not* blanket-implemented over all [`JsGeneric`]
/// types: each implementor explicitly opts in, which leaves room for future
/// wrapper types to pick a non-identity [`Self::JsCanon`].
///
/// # Example
///
/// ```ignore
/// use js_sys::{Array, Number};
///
/// let arr: Array<Number> = (0..10).map(Number::from).collect();
/// ```
pub trait IntoJsGeneric {
/// The canonical [`JsGeneric`] form of this type.
type JsCanon: JsGeneric;
/// Produce the canonical [`JsGeneric`] value for `self`.
fn to_js(self) -> Self::JsCanon;
}
impl IntoJsGeneric for JsValue {
type JsCanon = JsValue;
#[inline]
fn to_js(self) -> JsValue {
self
}
}
// Reference iteration clones the borrowed wrapper to produce an owned value,
// then delegates to that type's canonical conversion.
impl<T: IntoJsGeneric + Clone> IntoJsGeneric for &T {
type JsCanon = T::JsCanon;
#[inline]
fn to_js(self) -> T::JsCanon {
self.clone().to_js()
}
}
// Intentionally not a blanket `impl<T: JsGeneric> IntoJsGeneric for T`:
// that would lock in identity for every current and future `JsGeneric` type
// and prevent wrapper types from canonicalising to a different target.
// Instead, implementations are provided explicitly by each owning crate
// (macro-generated for user types; hand-written for `js_sys` containers).
+223
View File
@@ -0,0 +1,223 @@
//! 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::{__rt::marker::ErasableGeneric, Clamped, JsError, JsValue};
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
f32 => F32
f64 => F64
bool => BOOLEAN
char => CHAR
JsValue => EXTERNREF
}
// isize/usize map to I32/U32 on wasm32 and direct *_AS_F64 descriptors on wasm64
cfg_if! {
if #[cfg(target_arch = "wasm64")] {
simple! {
isize => I64_AS_F64
usize => U64_AS_F64
}
} else {
simple! {
isize => I32
usize => U32
}
}
}
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(RAW_POINTER)
}
}
impl<T> WasmDescribe for *mut T {
#[cfg_attr(wasm_bindgen_unstable_test_coverage, coverage(off))]
fn describe() {
inform(RAW_POINTER)
}
}
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();
}
}
+162
View File
@@ -0,0 +1,162 @@
use crate::__rt;
use crate::__rt::{WasmPtr, WasmWord};
use crate::JsValue;
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" {
// These intrinsics are replaced by the CLI with table.grow/table.set
// instructions, which always use i32 indices, even on wasm64.
fn __wbindgen_externref_table_grow(delta: i32) -> i32;
fn __wbindgen_externref_table_set_null(idx: u32) -> ();
}
}
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 as i32) };
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(target_arch = "wasm32")] {
// stable
core::arch::wasm32::unreachable();
} else if #[cfg(target_arch = "wasm64")] {
// unstable, need simd_wasm64 feature
core::arch::wasm64::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() -> u32 {
// Table indices are always 32-bit, even on wasm64.
HEAP_SLAB.0.borrow_mut().alloc() as u32
}
#[no_mangle]
pub extern "C" fn __externref_table_dealloc(idx: u32) {
let idx = idx as 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 as u32);
}
HEAP_SLAB.0.borrow_mut().dealloc(idx)
}
#[no_mangle]
pub unsafe extern "C" fn __externref_drop_slice(ptr: WasmPtr<JsValue>, len: WasmWord) {
let ptr = ptr.into_ptr();
let len = len.into_usize();
for slot in slice::from_raw_parts_mut(ptr, len) {
__externref_table_dealloc(slot.idx);
}
}
// 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()
}
+33
View File
@@ -0,0 +1,33 @@
//! Hooks for responding to hard-abort and reinit events on the Wasm instance.
//!
//! # Hard abort
//!
//! A hard abort occurs when the WebAssembly instance encounters a
//! non-recoverable error — an `unreachable` instruction, out-of-memory, or
//! stack overflow — that cannot be caught by Rust's `catch_unwind`. The
//! instance is poisoned and no further exports can be called.
//!
//! Use [`set_on_abort`] to register a callback that runs at the moment of
//! termination. Returns the previously registered handler (`None` if unset),
//! mirroring the `std::panic::set_hook` convention.
//!
//! **Only available when built with `panic=unwind`.**
//! [`set_on_abort`] returns `None` and the callback will never fire on
//! `panic=abort` builds. Support for `panic=abort` may be added in a future
//! release.
//!
//! # Reinit
//!
//! [`schedule_reinit()`] signals that the instance should be reinitialized.
//! The next call to any export detects this, creates a fresh
//! `WebAssembly.Instance` from the same module.
//!
//! Works with both `panic=unwind` and `panic=abort` builds.
//!
//! The reinit machinery is automatically emitted when [`schedule_reinit()`] is
//! used — no CLI flag is required. `--experimental-reset-state-function` is
//! only needed for the public `__wbg_reset_state()` export.
#[doc(hidden)]
pub use crate::__rt::schedule_reinit;
#[doc(hidden)]
pub use crate::__rt::set_on_abort;
File diff suppressed because it is too large Load Diff
+4
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() {}
+95
View File
@@ -0,0 +1,95 @@
//! `Parent<T>` — storage wrapper that backs the auto-injected `parent`
//! field of an exported Rust type declared with
//! `#[wasm_bindgen(extends = Parent)]`.
//!
//! Each parent method's wasm shim takes a `*const WasmRefCell<Parent>`,
//! while the child's `__wbg_ptr` points at a `WasmRefCell<Child>`.
//! The two pointers can't alias safely, so each JS instance carries a
//! separate `__wbg_ptr_<Class>` slot for every class in its inheritance
//! chain, and the parent data lives in its own `Rc<WasmRefCell<T>>`
//! allocation that the wasm runtime can clone on demand. `Parent<T>` is
//! that storage — a newtype around `Rc<WasmRefCell<T>>`.
//!
//! Users do **not** declare a `Parent<T>` field themselves. Writing
//! `#[wasm_bindgen(extends = Animal)] struct Dog { ... }` causes the macro
//! to inject `parent: wasm_bindgen::Parent<Animal>` as the first field of
//! `Dog`; an explicit user-declared `Parent<T>` field on any
//! `#[wasm_bindgen]` struct is rejected at macro time. In the child's
//! constructor the field is populated with `Animal::new(...).into()` (using
//! the [`From<T>`] impl below) or with [`Parent::new`]. From inside method
//! bodies the parent value is reached as `self.parent.borrow()` /
//! `self.parent.borrow_mut()`.
use crate::__rt::alloc::rc::Rc;
use crate::__rt::{Ref, RefMut, WasmRefCell};
/// Storage wrapper for the auto-injected `parent` field on a struct that
/// declares `#[wasm_bindgen(extends = Parent)]`.
///
/// Under the hood this is an `Rc<WasmRefCell<T>>` so that wasm-bindgen can
/// produce a separately-refcounted parent pointer for JS-side prototype
/// dispatch. Use [`Parent::borrow`] / [`Parent::borrow_mut`] to access the
/// inner value. You should not need to construct `Parent<T>` directly
/// outside the child's constructor; the [`From<T>`] impl is the typical way
/// to initialize the injected `parent` field.
///
/// `Clone` is a cheap `Rc` clone — both copies point at the same parent
/// data. `Debug` prints the wrapper plus the inner `T` (when `T: Debug`).
pub struct Parent<T> {
inner: Rc<WasmRefCell<T>>,
}
impl<T> Clone for Parent<T> {
fn clone(&self) -> Self {
Self {
inner: Rc::clone(&self.inner),
}
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for Parent<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("Parent")
.field(&*self.inner.borrow())
.finish()
}
}
impl<T> Parent<T> {
/// Wraps a value in a new `Parent<T>`.
pub fn new(value: T) -> Self {
Self {
inner: Rc::new(WasmRefCell::new(value)),
}
}
/// Immutably borrows the wrapped value.
///
/// Panics (or throws on the wasm target) if the value is currently
/// mutably borrowed.
pub fn borrow(&self) -> Ref<'_, T> {
self.inner.borrow()
}
/// Mutably borrows the wrapped value.
///
/// Panics (or throws on the wasm target) if the value is currently
/// borrowed.
pub fn borrow_mut(&self) -> RefMut<'_, T> {
self.inner.borrow_mut()
}
/// Internal accessor used by the `#[wasm_bindgen(extends = ...)]`
/// codegen to clone the inner `Rc` when producing an ancestor ABI
/// pointer for JS. Not part of the public API.
#[doc(hidden)]
pub fn __wbg_clone_rc(&self) -> Rc<WasmRefCell<T>> {
Rc::clone(&self.inner)
}
}
impl<T> From<T> for Parent<T> {
fn from(value: T) -> Self {
Parent::new(value)
}
}
+154
View File
@@ -0,0 +1,154 @@
/// 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",
all(target_family = "wasm", not(target_os = "wasi")),
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",
all(target_family = "wasm", not(target_os = "wasi")),
panic = "unwind"
))]
impl<T: UnwindSafe + ?Sized> MaybeUnwindSafe for T {}
#[cfg(not(all(
feature = "std",
all(target_family = "wasm", not(target_os = "wasi")),
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>,
{
}
File diff suppressed because it is too large Load Diff
+272
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::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" {
/// An optional JS value of type `T`.
///
/// Unlike `Option<T>`, which is a Rust-side construct, `JsOption<T>` represents
/// a JS value that may be `T` or `undefined`, where the presence 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).
///
/// Only `undefined` is treated as absent, matching TypeScript's `T | undefined`.
/// JavaScript `null` is a distinct present value.
///
/// `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: JsGeneric> JsOption<T> {
/// Creates an empty `JsOption<T>` representing `undefined`.
#[inline]
pub fn new() -> Self {
Undefined::UNDEFINED.unchecked_into()
}
/// Wraps a value in a `JsOption<T>`.
#[inline]
pub fn wrap(val: T) -> Self {
val.unchecked_into()
}
/// 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 (`undefined`).
#[inline]
pub fn is_empty(&self) -> bool {
JsValue::is_undefined(self)
}
/// Converts this `JsOption<T>` to an `Option<T>` by cloning the inner value.
///
/// Returns `None` if the value is `undefined`, otherwise returns
/// `Some(T)` with a clone of the contained value.
#[inline]
pub fn as_option(&self) -> Option<T> {
if JsValue::is_undefined(self) {
None
} else {
let cloned = self.deref().clone();
Some(cloned.unchecked_into())
}
}
/// Converts this `JsOption<T>` into an `Option<T>`, consuming `self`.
///
/// Returns `None` if the value is `undefined`, otherwise returns
/// `Some(T)` with the contained value.
#[inline]
pub fn into_option(self) -> Option<T> {
if JsValue::is_undefined(&self) {
None
} else {
Some(self.unchecked_into())
}
}
/// Returns the contained value, consuming `self`.
///
/// # Panics
///
/// Panics if the value is `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 `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 `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 `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("undefined")?,
}
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("undefined")?,
}
f.write_str(")")
}
}
impl UpcastFrom<JsValue> for JsOption<JsValue> {}
impl<T> UpcastFrom<Undefined> 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> {}