mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-15 05:51:23 +00:00
Merge branch 'master' into variadic_js_functions
This commit is contained in:
@ -19,7 +19,7 @@ build: false
|
|||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- rustup target add wasm32-unknown-unknown
|
- rustup target add wasm32-unknown-unknown
|
||||||
- npm ci
|
- npm install
|
||||||
- cargo test
|
- cargo test
|
||||||
- cargo build --release -p wasm-bindgen-cli
|
- cargo build --release -p wasm-bindgen-cli
|
||||||
- where chromedriver
|
- where chromedriver
|
||||||
@ -31,6 +31,7 @@ test_script:
|
|||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
- /^\d/
|
||||||
|
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- ps: |
|
- ps: |
|
||||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ package-lock.json
|
|||||||
npm-shrinkwrap.json
|
npm-shrinkwrap.json
|
||||||
yarn.lock
|
yarn.lock
|
||||||
*.d.ts
|
*.d.ts
|
||||||
|
/publish
|
||||||
|
/publish.exe
|
||||||
|
16
.travis.yml
16
.travis.yml
@ -4,6 +4,7 @@ sudo: false
|
|||||||
INSTALL_NODE_VIA_NVM: &INSTALL_NODE_VIA_NVM
|
INSTALL_NODE_VIA_NVM: &INSTALL_NODE_VIA_NVM
|
||||||
|
|
|
|
||||||
rustup target add wasm32-unknown-unknown
|
rustup target add wasm32-unknown-unknown
|
||||||
|
rustup component add llvm-tools-preview
|
||||||
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
|
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
|
||||||
source ~/.nvm/nvm.sh
|
source ~/.nvm/nvm.sh
|
||||||
nvm install v10.5
|
nvm install v10.5
|
||||||
@ -56,6 +57,7 @@ matrix:
|
|||||||
- cargo test
|
- cargo test
|
||||||
# Run the main body of the test suite
|
# Run the main body of the test suite
|
||||||
- cargo test --target wasm32-unknown-unknown
|
- cargo test --target wasm32-unknown-unknown
|
||||||
|
- cargo test --target wasm32-unknown-unknown --features nightly
|
||||||
# Rerun the test suite but disable `--debug` in generated JS
|
# Rerun the test suite but disable `--debug` in generated JS
|
||||||
- WASM_BINDGEN_NO_DEBUG=1 cargo test --target wasm32-unknown-unknown
|
- WASM_BINDGEN_NO_DEBUG=1 cargo test --target wasm32-unknown-unknown
|
||||||
# Make sure our serde tests work
|
# Make sure our serde tests work
|
||||||
@ -74,7 +76,7 @@ matrix:
|
|||||||
env: JOB=examples-build
|
env: JOB=examples-build
|
||||||
install:
|
install:
|
||||||
- *INSTALL_NODE_VIA_NVM
|
- *INSTALL_NODE_VIA_NVM
|
||||||
- npm ci --verbose
|
- npm install
|
||||||
script:
|
script:
|
||||||
- |
|
- |
|
||||||
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v no_modules`; do
|
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v no_modules`; do
|
||||||
@ -118,18 +120,6 @@ matrix:
|
|||||||
chrome: stable
|
chrome: stable
|
||||||
if: branch = master
|
if: branch = master
|
||||||
|
|
||||||
# Tests pass on nightly using yarn
|
|
||||||
- rust: nightly
|
|
||||||
env: JOB=test-yarn-smoke
|
|
||||||
install:
|
|
||||||
- *INSTALL_NODE_VIA_NVM
|
|
||||||
- travis_retry curl -OLSf https://yarnpkg.com/install.sh
|
|
||||||
- travis_retry bash install.sh -- --version 1.7.0
|
|
||||||
- export PATH=$HOME/.yarn/bin:$PATH
|
|
||||||
- yarn install --freeze-lockfile
|
|
||||||
script: cargo test api::works
|
|
||||||
if: branch = master
|
|
||||||
|
|
||||||
# WebIDL tests pass on nightly
|
# WebIDL tests pass on nightly
|
||||||
- rust: nightly
|
- rust: nightly
|
||||||
env: JOB=test-webidl
|
env: JOB=test-webidl
|
||||||
|
30
CHANGELOG.md
30
CHANGELOG.md
@ -32,6 +32,36 @@ Released YYYY-MM-DD.
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## 0.2.19 (and 0.2.18)
|
||||||
|
|
||||||
|
Released 2018-08-27.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Added bindings to `js-sys` for some `WebAssembly` types.
|
||||||
|
* Added bindings to `js-sys` for some `Intl` types.
|
||||||
|
* Added bindings to `js-sys` for some `String` methods.
|
||||||
|
* Added an example of using the WebAudio APIs.
|
||||||
|
* Added an example of using the `fetch` API.
|
||||||
|
* Added more `extends` annotations for types in `js-sys`.
|
||||||
|
* Experimental support for `WeakRef` was added to automatically deallocate Rust
|
||||||
|
objects when gc'd.
|
||||||
|
* Added support for executing `wasm-bindgen` over modules that import their
|
||||||
|
memory.
|
||||||
|
* Added a global `memory()` function in the `wasm-bindgen` crate for accessing
|
||||||
|
the JS object that represent wasm's own memory.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
* Removed `AsMut` implementations for imported objects.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fixed the `constructor` and `catch` attributes combined on imported types.
|
||||||
|
* Fixed importing the same-named static in two modules.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
## 0.2.17
|
## 0.2.17
|
||||||
|
|
||||||
Released 2018-08-16.
|
Released 2018-08-16.
|
||||||
|
18
Cargo.toml
18
Cargo.toml
@ -1,8 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
|
# Because only a single `wasm_bindgen` version can be used in a dependency
|
||||||
|
# graph, pretend we link a native library so that `cargo` will provide better
|
||||||
|
# error messages than the esoteric linker errors we would otherwise trigger.
|
||||||
|
links = "wasm_bindgen"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen"
|
repository = "https://github.com/rustwasm/wasm-bindgen"
|
||||||
@ -21,21 +25,23 @@ default = ["spans", "std"]
|
|||||||
spans = ["wasm-bindgen-macro/spans"]
|
spans = ["wasm-bindgen-macro/spans"]
|
||||||
std = []
|
std = []
|
||||||
serde-serialize = ["serde", "serde_json", "std"]
|
serde-serialize = ["serde", "serde_json", "std"]
|
||||||
|
nightly = []
|
||||||
|
|
||||||
# This is only for debugging wasm-bindgen! No stability guarantees, so enable
|
# This is only for debugging wasm-bindgen! No stability guarantees, so enable
|
||||||
# this at your own peril!
|
# this at your own peril!
|
||||||
xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_generated_code"]
|
xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_generated_code"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.17" }
|
wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.19" }
|
||||||
serde = { version = "1.0", optional = true }
|
serde = { version = "1.0", optional = true }
|
||||||
serde_json = { version = "1.0", optional = true }
|
serde_json = { version = "1.0", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
wasm-bindgen-test = { path = 'crates/test', version = '=0.2.17' }
|
js-sys = { path = 'crates/js-sys', version = '0.2.4' }
|
||||||
|
wasm-bindgen-test = { path = 'crates/test', version = '=0.2.19' }
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
|
wasm-bindgen-test-crate-a = { path = 'tests/crates/a', version = '0.1' }
|
||||||
wasm-bindgen-test-crate-b = { path = 'tests/crates/b' }
|
wasm-bindgen-test-crate-b = { path = 'tests/crates/b', version = '0.1' }
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
@ -56,6 +62,7 @@ members = [
|
|||||||
"examples/comments",
|
"examples/comments",
|
||||||
"examples/console_log",
|
"examples/console_log",
|
||||||
"examples/dom",
|
"examples/dom",
|
||||||
|
"examples/fetch",
|
||||||
"examples/guide-supported-types-examples",
|
"examples/guide-supported-types-examples",
|
||||||
"examples/hello_world",
|
"examples/hello_world",
|
||||||
"examples/import_js",
|
"examples/import_js",
|
||||||
@ -65,6 +72,7 @@ members = [
|
|||||||
"examples/performance",
|
"examples/performance",
|
||||||
"examples/smorgasboard",
|
"examples/smorgasboard",
|
||||||
"examples/wasm-in-wasm",
|
"examples/wasm-in-wasm",
|
||||||
|
"examples/webaudio",
|
||||||
"tests/no-std",
|
"tests/no-std",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
23
README.md
23
README.md
@ -13,8 +13,6 @@
|
|||||||
Import JavaScript things into Rust and export Rust things to JavaScript.
|
Import JavaScript things into Rust and export Rust things to JavaScript.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
@ -40,6 +38,27 @@ import { greet } from "./hello_world";
|
|||||||
greet("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 ["host bindings" proposal][host-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
|
||||||
|
[host-bindings]: https://github.com/WebAssembly/host-bindings/blob/master/proposals/host-bindings/Overview.md
|
||||||
|
|
||||||
## Guide
|
## Guide
|
||||||
|
|
||||||
[📚 Read the `wasm-bindgen` guide here! 📚](https://rustwasm.github.io/wasm-bindgen)
|
[📚 Read the `wasm-bindgen` guide here! 📚](https://rustwasm.github.io/wasm-bindgen)
|
||||||
|
2
build.rs
Normal file
2
build.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
// Empty `build.rs` so that `[package] links = ...` works in `Cargo.toml`.
|
||||||
|
fn main() {}
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend"
|
||||||
@ -11,7 +11,7 @@ Backend code generation of the wasm-bindgen tool
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
spans = ["proc-macro2/nightly"]
|
spans = []
|
||||||
extra-traits = ["syn/extra-traits"]
|
extra-traits = ["syn/extra-traits"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -21,4 +21,4 @@ proc-macro2 = "0.4.8"
|
|||||||
quote = '0.6'
|
quote = '0.6'
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
syn = { version = '0.14', features = ['full', 'visit'] }
|
syn = { version = '0.14', features = ['full', 'visit'] }
|
||||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.17" }
|
wasm-bindgen-shared = { path = "../shared", version = "=0.2.19" }
|
||||||
|
@ -100,6 +100,10 @@ pub enum ImportFunctionKind {
|
|||||||
ty: syn::Type,
|
ty: syn::Type,
|
||||||
kind: MethodKind,
|
kind: MethodKind,
|
||||||
},
|
},
|
||||||
|
ScopedMethod {
|
||||||
|
ty: syn::Type,
|
||||||
|
operation: Operation,
|
||||||
|
},
|
||||||
Normal,
|
Normal,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +412,29 @@ impl ImportFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn shared(&self) -> shared::ImportFunction {
|
fn shared(&self) -> shared::ImportFunction {
|
||||||
|
let shared_operation = |operation: &Operation| {
|
||||||
|
let is_static = operation.is_static;
|
||||||
|
let kind = match &operation.kind {
|
||||||
|
OperationKind::Regular => shared::OperationKind::Regular,
|
||||||
|
OperationKind::Getter(g) => {
|
||||||
|
let g = g.as_ref().map(|g| g.to_string());
|
||||||
|
shared::OperationKind::Getter(
|
||||||
|
g.unwrap_or_else(|| self.infer_getter_property()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OperationKind::Setter(s) => {
|
||||||
|
let s = s.as_ref().map(|s| s.to_string());
|
||||||
|
shared::OperationKind::Setter(
|
||||||
|
s.unwrap_or_else(|| self.infer_setter_property()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OperationKind::IndexingGetter => shared::OperationKind::IndexingGetter,
|
||||||
|
OperationKind::IndexingSetter => shared::OperationKind::IndexingSetter,
|
||||||
|
OperationKind::IndexingDeleter => shared::OperationKind::IndexingDeleter,
|
||||||
|
};
|
||||||
|
shared::Operation { is_static, kind }
|
||||||
|
};
|
||||||
|
|
||||||
let method = match self.kind {
|
let method = match self.kind {
|
||||||
ImportFunctionKind::Method {
|
ImportFunctionKind::Method {
|
||||||
ref class,
|
ref class,
|
||||||
@ -416,34 +443,21 @@ impl ImportFunction {
|
|||||||
} => {
|
} => {
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
MethodKind::Constructor => shared::MethodKind::Constructor,
|
MethodKind::Constructor => shared::MethodKind::Constructor,
|
||||||
MethodKind::Operation(Operation { is_static, kind }) => {
|
MethodKind::Operation(op) => {
|
||||||
let is_static = *is_static;
|
shared::MethodKind::Operation(shared_operation(op))
|
||||||
let kind = match kind {
|
|
||||||
OperationKind::Regular => shared::OperationKind::Regular,
|
|
||||||
OperationKind::Getter(g) => {
|
|
||||||
let g = g.as_ref().map(|g| g.to_string());
|
|
||||||
shared::OperationKind::Getter(
|
|
||||||
g.unwrap_or_else(|| self.infer_getter_property()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
OperationKind::Setter(s) => {
|
|
||||||
let s = s.as_ref().map(|s| s.to_string());
|
|
||||||
shared::OperationKind::Setter(
|
|
||||||
s.unwrap_or_else(|| self.infer_setter_property()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
OperationKind::IndexingGetter => shared::OperationKind::IndexingGetter,
|
|
||||||
OperationKind::IndexingSetter => shared::OperationKind::IndexingSetter,
|
|
||||||
OperationKind::IndexingDeleter => shared::OperationKind::IndexingDeleter,
|
|
||||||
};
|
|
||||||
shared::MethodKind::Operation(shared::Operation { is_static, kind })
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Some(shared::MethodData {
|
Some(shared::MethodData {
|
||||||
class: class.clone(),
|
class: Some(class.clone()),
|
||||||
kind,
|
kind,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ImportFunctionKind::ScopedMethod { ref operation, .. } => {
|
||||||
|
Some(shared::MethodData {
|
||||||
|
class: None,
|
||||||
|
kind: shared::MethodKind::Operation(shared_operation(operation)),
|
||||||
|
})
|
||||||
|
}
|
||||||
ImportFunctionKind::Normal => None,
|
ImportFunctionKind::Normal => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -618,9 +618,6 @@ impl ToTokens for ast::ImportType {
|
|||||||
fn as_ref(&self) -> &JsValue { &self.obj }
|
fn as_ref(&self) -> &JsValue { &self.obj }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<JsValue> for #rust_name {
|
|
||||||
fn as_mut(&mut self) -> &mut JsValue { &mut self.obj }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<#rust_name> for JsValue {
|
impl From<#rust_name> for JsValue {
|
||||||
fn from(obj: #rust_name) -> JsValue {
|
fn from(obj: #rust_name) -> JsValue {
|
||||||
@ -656,12 +653,6 @@ impl ToTokens for ast::ImportType {
|
|||||||
// wrapper around `val`
|
// wrapper around `val`
|
||||||
unsafe { &*(val as *const JsValue as *const #rust_name) }
|
unsafe { &*(val as *const JsValue as *const #rust_name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self {
|
|
||||||
// Should be safe because `#rust_name` is a transparent
|
|
||||||
// wrapper around `val`
|
|
||||||
unsafe { &mut *(val as *mut JsValue as *mut #rust_name) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
()
|
()
|
||||||
@ -683,13 +674,6 @@ impl ToTokens for ast::ImportType {
|
|||||||
#superclass::unchecked_from_js_ref(self.as_ref())
|
#superclass::unchecked_from_js_ref(self.as_ref())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<#superclass> for #rust_name {
|
|
||||||
fn as_mut(&mut self) -> &mut #superclass {
|
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
#superclass::unchecked_from_js_mut(self.as_mut())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).to_tokens(tokens);
|
}).to_tokens(tokens);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -800,6 +784,9 @@ impl TryToTokens for ast::ImportFunction {
|
|||||||
}
|
}
|
||||||
class_ty = Some(ty);
|
class_ty = Some(ty);
|
||||||
}
|
}
|
||||||
|
ast::ImportFunctionKind::ScopedMethod { ref ty, .. } => {
|
||||||
|
class_ty = Some(ty);
|
||||||
|
}
|
||||||
ast::ImportFunctionKind::Normal => {}
|
ast::ImportFunctionKind::Normal => {}
|
||||||
}
|
}
|
||||||
let vis = &self.function.rust_vis;
|
let vis = &self.function.rust_vis;
|
||||||
@ -1191,9 +1178,6 @@ impl ToTokens for ast::Dictionary {
|
|||||||
impl AsRef<JsValue> for #name {
|
impl AsRef<JsValue> for #name {
|
||||||
fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
|
fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
|
||||||
}
|
}
|
||||||
impl AsMut<JsValue> for #name {
|
|
||||||
fn as_mut(&mut self) -> &mut JsValue { self.obj.as_mut() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Boundary conversion impls
|
// Boundary conversion impls
|
||||||
impl WasmDescribe for #name {
|
impl WasmDescribe for #name {
|
||||||
@ -1257,10 +1241,6 @@ impl ToTokens for ast::Dictionary {
|
|||||||
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
|
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
|
||||||
unsafe { &*(val as *const JsValue as *const #name) }
|
unsafe { &*(val as *const JsValue as *const #name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unchecked_from_js_mut(val: &mut JsValue) -> &mut Self {
|
|
||||||
unsafe { &mut *(val as *mut JsValue as *mut #name) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}).to_tokens(tokens);
|
}).to_tokens(tokens);
|
||||||
|
@ -246,6 +246,7 @@ impl ImportedTypes for ast::ImportFunctionKind {
|
|||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
|
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
|
||||||
|
ast::ImportFunctionKind::ScopedMethod { ty, .. } => ty.imported_types(f),
|
||||||
ast::ImportFunctionKind::Normal => {}
|
ast::ImportFunctionKind::Normal => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-cli-support"
|
name = "wasm-bindgen-cli-support"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli-support"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli-support"
|
||||||
@ -13,10 +13,10 @@ Shared support for the wasm-bindgen-cli package, an internal dependency
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.9"
|
base64 = "0.9"
|
||||||
failure = "0.1.2"
|
failure = "0.1.2"
|
||||||
parity-wasm = "0.31"
|
parity-wasm = "0.32"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
tempfile = "3.0"
|
tempfile = "3.0"
|
||||||
wasm-bindgen-shared = { path = "../shared", version = '=0.2.17' }
|
wasm-bindgen-shared = { path = "../shared", version = '=0.2.19' }
|
||||||
|
wasm-bindgen-wasm-interpreter = { path = "../wasm-interpreter", version = '=0.2.19' }
|
||||||
wasm-gc-api = "0.1.9"
|
wasm-gc-api = "0.1.9"
|
||||||
wasmi = "0.3"
|
|
||||||
|
@ -94,7 +94,7 @@ pub enum VectorKind {
|
|||||||
impl Descriptor {
|
impl Descriptor {
|
||||||
pub fn decode(mut data: &[u32]) -> Descriptor {
|
pub fn decode(mut data: &[u32]) -> Descriptor {
|
||||||
let descriptor = Descriptor::_decode(&mut data);
|
let descriptor = Descriptor::_decode(&mut data);
|
||||||
assert!(data.is_empty());
|
assert!(data.is_empty(), "remaining data {:?}", data);
|
||||||
descriptor
|
descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ use wasm_gc;
|
|||||||
|
|
||||||
use super::Bindgen;
|
use super::Bindgen;
|
||||||
use descriptor::{Descriptor, VectorKind};
|
use descriptor::{Descriptor, VectorKind};
|
||||||
|
use wasm_interpreter::Interpreter;
|
||||||
|
|
||||||
mod js2rust;
|
mod js2rust;
|
||||||
use self::js2rust::Js2Rust;
|
use self::js2rust::Js2Rust;
|
||||||
@ -23,6 +24,8 @@ pub struct Context<'a> {
|
|||||||
pub typescript: String,
|
pub typescript: String,
|
||||||
pub exposed_globals: HashSet<&'static str>,
|
pub exposed_globals: HashSet<&'static str>,
|
||||||
pub required_internal_exports: HashSet<&'static str>,
|
pub required_internal_exports: HashSet<&'static str>,
|
||||||
|
pub imported_functions: HashSet<String>,
|
||||||
|
pub imported_statics: HashSet<String>,
|
||||||
pub config: &'a Bindgen,
|
pub config: &'a Bindgen,
|
||||||
pub module: &'a mut Module,
|
pub module: &'a mut Module,
|
||||||
|
|
||||||
@ -41,7 +44,8 @@ pub struct Context<'a> {
|
|||||||
|
|
||||||
pub exported_classes: HashMap<String, ExportedClass>,
|
pub exported_classes: HashMap<String, ExportedClass>,
|
||||||
pub function_table_needed: bool,
|
pub function_table_needed: bool,
|
||||||
pub run_descriptor: &'a Fn(&str) -> Option<Vec<u32>>,
|
pub interpreter: &'a mut Interpreter,
|
||||||
|
pub memory_init: Option<ResizableLimits>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -376,6 +380,19 @@ impl<'a> Context<'a> {
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
self.bind("__wbindgen_memory", &|me| {
|
||||||
|
me.expose_add_heap_object();
|
||||||
|
let mem = me.memory();
|
||||||
|
Ok(format!(
|
||||||
|
"
|
||||||
|
function() {{
|
||||||
|
return addHeapObject({});
|
||||||
|
}}
|
||||||
|
", mem
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
self.create_memory_export();
|
||||||
self.unexport_unused_internal_exports();
|
self.unexport_unused_internal_exports();
|
||||||
self.gc()?;
|
self.gc()?;
|
||||||
|
|
||||||
@ -490,6 +507,39 @@ impl<'a> Context<'a> {
|
|||||||
let mut dst = format!("class {} {{\n", name);
|
let mut dst = format!("class {} {{\n", name);
|
||||||
let mut ts_dst = format!("export {}", dst);
|
let mut ts_dst = format!("export {}", dst);
|
||||||
|
|
||||||
|
let (mkweakref, freeref) = if self.config.weak_refs {
|
||||||
|
// When weak refs are enabled we use them to automatically free the
|
||||||
|
// contents of an exported rust class when it's gc'd. Note that a
|
||||||
|
// manual `free` function still exists for deterministic
|
||||||
|
// destruction.
|
||||||
|
//
|
||||||
|
// This is implemented by using a `WeakRefGroup` to run finalizers
|
||||||
|
// for all `WeakRef` objects that it creates. Upon construction of
|
||||||
|
// a new wasm object we use `makeRef` with "holdings" of a thunk to
|
||||||
|
// free the wasm instance. Once the `this` (the instance we're
|
||||||
|
// creating) is gc'd then the finalizer will run with the
|
||||||
|
// `WeakRef`, and we'll pull out the `holdings`, our pointer.
|
||||||
|
//
|
||||||
|
// Note, though, that if manual finalization happens we want to
|
||||||
|
// cancel the `WeakRef`-generated finalization, so we retain the
|
||||||
|
// `WeakRef` in a global map. This global map is then used to
|
||||||
|
// `drop()` the `WeakRef` (cancel finalization) whenever it is
|
||||||
|
// finalized.
|
||||||
|
self.expose_cleanup_groups();
|
||||||
|
let mk = format!("
|
||||||
|
const cleanup_ptr = this.ptr;
|
||||||
|
const ref = CLEANUPS.makeRef(this, () => free{}(cleanup_ptr));
|
||||||
|
CLEANUPS_MAP.set(this.ptr, ref);
|
||||||
|
", name);
|
||||||
|
let free = "
|
||||||
|
CLEANUPS_MAP.get(ptr).drop();
|
||||||
|
CLEANUPS_MAP.delete(ptr);
|
||||||
|
";
|
||||||
|
(mk, free)
|
||||||
|
} else {
|
||||||
|
(String::new(), "")
|
||||||
|
};
|
||||||
|
|
||||||
if self.config.debug || class.constructor.is_some() {
|
if self.config.debug || class.constructor.is_some() {
|
||||||
self.expose_constructor_token();
|
self.expose_constructor_token();
|
||||||
|
|
||||||
@ -516,9 +566,11 @@ impl<'a> Context<'a> {
|
|||||||
// This invocation of new will call this constructor with a ConstructorToken
|
// This invocation of new will call this constructor with a ConstructorToken
|
||||||
let instance = {class}.{constructor}(...args);
|
let instance = {class}.{constructor}(...args);
|
||||||
this.ptr = instance.ptr;
|
this.ptr = instance.ptr;
|
||||||
|
{mkweakref}
|
||||||
",
|
",
|
||||||
class = name,
|
class = name,
|
||||||
constructor = constructor
|
constructor = constructor,
|
||||||
|
mkweakref = mkweakref,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
dst.push_str(
|
dst.push_str(
|
||||||
@ -537,9 +589,11 @@ impl<'a> Context<'a> {
|
|||||||
|
|
||||||
constructor(ptr) {{
|
constructor(ptr) {{
|
||||||
this.ptr = ptr;
|
this.ptr = ptr;
|
||||||
|
{}
|
||||||
}}
|
}}
|
||||||
",
|
",
|
||||||
name
|
name,
|
||||||
|
mkweakref,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,15 +653,26 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.global(&format!(
|
||||||
|
"
|
||||||
|
function free{}(ptr) {{
|
||||||
|
{}
|
||||||
|
wasm.{}(ptr);
|
||||||
|
}}
|
||||||
|
",
|
||||||
|
name,
|
||||||
|
freeref,
|
||||||
|
shared::free_function(&name)
|
||||||
|
));
|
||||||
dst.push_str(&format!(
|
dst.push_str(&format!(
|
||||||
"
|
"
|
||||||
free() {{
|
free() {{
|
||||||
const ptr = this.ptr;
|
const ptr = this.ptr;
|
||||||
this.ptr = 0;
|
this.ptr = 0;
|
||||||
wasm.{}(ptr);
|
free{}(ptr);
|
||||||
}}
|
}}
|
||||||
",
|
",
|
||||||
shared::free_function(&name)
|
name,
|
||||||
));
|
));
|
||||||
ts_dst.push_str("free(): void;\n");
|
ts_dst.push_str("free(): void;\n");
|
||||||
dst.push_str(&class.contents);
|
dst.push_str(&class.contents);
|
||||||
@ -636,6 +701,20 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_memory_export(&mut self) {
|
||||||
|
let limits = match self.memory_init.clone() {
|
||||||
|
Some(limits) => limits,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
let mut initializer = String::from("new WebAssembly.Memory({");
|
||||||
|
initializer.push_str(&format!("initial:{}", limits.initial()));
|
||||||
|
if let Some(max) = limits.maximum() {
|
||||||
|
initializer.push_str(&format!(",maximum:{}", max));
|
||||||
|
}
|
||||||
|
initializer.push_str("})");
|
||||||
|
self.export("memory", &initializer, None);
|
||||||
|
}
|
||||||
|
|
||||||
fn rewrite_imports(&mut self, module_name: &str) {
|
fn rewrite_imports(&mut self, module_name: &str) {
|
||||||
for (name, contents) in self._rewrite_imports(module_name) {
|
for (name, contents) in self._rewrite_imports(module_name) {
|
||||||
self.export(&name, &contents, None);
|
self.export(&name, &contents, None);
|
||||||
@ -666,6 +745,15 @@ impl<'a> Context<'a> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If memory is imported we'll have exported it from the shim module
|
||||||
|
// so let's import it from there.
|
||||||
|
if import.field() == "memory" {
|
||||||
|
import.module_mut().truncate(0);
|
||||||
|
import.module_mut().push_str("./");
|
||||||
|
import.module_mut().push_str(module_name);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
let renamed_import = format!("__wbindgen_{}", import.field());
|
let renamed_import = format!("__wbindgen_{}", import.field());
|
||||||
let mut bind_math = |expr: &str| {
|
let mut bind_math = |expr: &str| {
|
||||||
math_imports.push((renamed_import.clone(), format!("function{}", expr)));
|
math_imports.push((renamed_import.clone(), format!("function{}", expr)));
|
||||||
@ -1091,13 +1179,30 @@ impl<'a> Context<'a> {
|
|||||||
}
|
}
|
||||||
self.expose_text_decoder();
|
self.expose_text_decoder();
|
||||||
self.expose_uint8_memory();
|
self.expose_uint8_memory();
|
||||||
self.global(
|
|
||||||
"
|
// Typically we try to give a raw view of memory out to `TextDecoder` to
|
||||||
function getStringFromWasm(ptr, len) {
|
// avoid copying too much data. If, however, a `SharedArrayBuffer` is
|
||||||
return cachedDecoder.decode(getUint8Memory().subarray(ptr, ptr + len));
|
// being used it looks like that is rejected by `TextDecoder` or
|
||||||
}
|
// otherwise doesn't work with it. When we detect a shared situation we
|
||||||
",
|
// use `slice` which creates a new array instead of `subarray` which
|
||||||
);
|
// creates just a view. That way in shared mode we copy more data but in
|
||||||
|
// non-shared mode there's no need to copy the data except for the
|
||||||
|
// string itself.
|
||||||
|
self.memory(); // set self.memory_init
|
||||||
|
let is_shared = self.module
|
||||||
|
.memory_section()
|
||||||
|
.map(|s| s.entries()[0].limits().shared())
|
||||||
|
.unwrap_or(match &self.memory_init {
|
||||||
|
Some(limits) => limits.shared(),
|
||||||
|
None => false,
|
||||||
|
});
|
||||||
|
let method = if is_shared { "slice" } else { "subarray" };
|
||||||
|
|
||||||
|
self.global(&format!("
|
||||||
|
function getStringFromWasm(ptr, len) {{
|
||||||
|
return cachedDecoder.decode(getUint8Memory().{}(ptr, ptr + len));
|
||||||
|
}}
|
||||||
|
", method));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expose_get_array_js_value_from_wasm(&mut self) {
|
fn expose_get_array_js_value_from_wasm(&mut self) {
|
||||||
@ -1284,18 +1389,20 @@ impl<'a> Context<'a> {
|
|||||||
if !self.exposed_globals.insert(name) {
|
if !self.exposed_globals.insert(name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let mem = self.memory();
|
||||||
self.global(&format!(
|
self.global(&format!(
|
||||||
"
|
"
|
||||||
let cache{name} = null;
|
let cache{name} = null;
|
||||||
function {name}() {{
|
function {name}() {{
|
||||||
if (cache{name} === null || cache{name}.buffer !== wasm.memory.buffer) {{
|
if (cache{name} === null || cache{name}.buffer !== {mem}.buffer) {{
|
||||||
cache{name} = new {js}(wasm.memory.buffer);
|
cache{name} = new {js}({mem}.buffer);
|
||||||
}}
|
}}
|
||||||
return cache{name};
|
return cache{name};
|
||||||
}}
|
}}
|
||||||
",
|
",
|
||||||
name = name,
|
name = name,
|
||||||
js = js,
|
js = js,
|
||||||
|
mem = mem,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1594,6 +1701,18 @@ impl<'a> Context<'a> {
|
|||||||
");
|
");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expose_cleanup_groups(&mut self) {
|
||||||
|
if !self.exposed_globals.insert("cleanup_groups") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.global(
|
||||||
|
"
|
||||||
|
const CLEANUPS = new WeakRefGroup(x => x.holdings());
|
||||||
|
const CLEANUPS_MAP = new Map();
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn gc(&mut self) -> Result<(), Error> {
|
fn gc(&mut self) -> Result<(), Error> {
|
||||||
let module = mem::replace(self.module, Module::default());
|
let module = mem::replace(self.module, Module::default());
|
||||||
let module = module.parse_names().unwrap_or_else(|p| p.1);
|
let module = module.parse_names().unwrap_or_else(|p| p.1);
|
||||||
@ -1608,9 +1727,9 @@ impl<'a> Context<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn describe(&self, name: &str) -> Option<Descriptor> {
|
fn describe(&mut self, name: &str) -> Option<Descriptor> {
|
||||||
let name = format!("__wbindgen_describe_{}", name);
|
let name = format!("__wbindgen_describe_{}", name);
|
||||||
(self.run_descriptor)(&name).map(|d| Descriptor::decode(&d))
|
Some(Descriptor::decode(self.interpreter.interpret(&name, self.module)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn global(&mut self, s: &str) {
|
fn global(&mut self, s: &str) {
|
||||||
@ -1628,6 +1747,29 @@ impl<'a> Context<'a> {
|
|||||||
fn use_node_require(&self) -> bool {
|
fn use_node_require(&self) -> bool {
|
||||||
self.config.nodejs && !self.config.nodejs_experimental_modules
|
self.config.nodejs && !self.config.nodejs_experimental_modules
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn memory(&mut self) -> &'static str {
|
||||||
|
if self.module.memory_section().is_some() {
|
||||||
|
return "wasm.memory";
|
||||||
|
}
|
||||||
|
|
||||||
|
let (entry, mem) = self.module.import_section()
|
||||||
|
.expect("must import memory")
|
||||||
|
.entries()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|i| {
|
||||||
|
match i.external() {
|
||||||
|
External::Memory(m) => Some((i, m)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
.expect("must import memory");
|
||||||
|
assert_eq!(entry.module(), "env");
|
||||||
|
assert_eq!(entry.field(), "memory");
|
||||||
|
self.memory_init = Some(mem.limits().clone());
|
||||||
|
"memory"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> SubContext<'a, 'b> {
|
impl<'a, 'b> SubContext<'a, 'b> {
|
||||||
@ -1772,6 +1914,12 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
info: &shared::Import,
|
info: &shared::Import,
|
||||||
import: &shared::ImportStatic,
|
import: &shared::ImportStatic,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
// The same static can be imported in multiple locations, so only
|
||||||
|
// generate bindings once for it.
|
||||||
|
if !self.cx.imported_statics.insert(import.shim.clone()) {
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: should support more types to import here
|
// TODO: should support more types to import here
|
||||||
let obj = self.import_name(info, &import.name)?;
|
let obj = self.import_name(info, &import.name)?;
|
||||||
self.cx.expose_add_heap_object();
|
self.cx.expose_add_heap_object();
|
||||||
@ -1799,132 +1947,39 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It's possible for the same function to be imported in two locations,
|
||||||
|
// but we only want to generate one.
|
||||||
|
if !self.cx.imported_functions.insert(import.shim.clone()) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let descriptor = match self.cx.describe(&import.shim) {
|
let descriptor = match self.cx.describe(&import.shim) {
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
Some(d) => d,
|
Some(d) => d,
|
||||||
};
|
};
|
||||||
|
|
||||||
let target = match &import.method {
|
let target = self.generated_import_target(info, import, &descriptor)?;
|
||||||
Some(shared::MethodData { class, kind }) => {
|
|
||||||
let class = self.import_name(info, class)?;
|
|
||||||
match kind {
|
|
||||||
shared::MethodKind::Constructor => format!("new {}", class),
|
|
||||||
shared::MethodKind::Operation(shared::Operation { is_static, kind }) => {
|
|
||||||
let target = if import.structural {
|
|
||||||
let location = if *is_static { &class } else { "this" };
|
|
||||||
|
|
||||||
match kind {
|
let js = Rust2Js::new(self.cx)
|
||||||
shared::OperationKind::Regular => {
|
.catch(import.catch)
|
||||||
let nargs = descriptor.unwrap_function().arguments.len();
|
.variadic(import.variadic)
|
||||||
let mut s = format!("function(");
|
.process(descriptor.unwrap_function())?
|
||||||
for i in 0..nargs - 1 {
|
.finish(&target);
|
||||||
if i > 0 {
|
self.cx.export(&import.shim, &js, None);
|
||||||
drop(write!(s, ", "));
|
Ok(())
|
||||||
}
|
}
|
||||||
drop(write!(s, "x{}", i));
|
|
||||||
}
|
|
||||||
s.push_str(") { \nreturn this.");
|
|
||||||
s.push_str(&import.function.name);
|
|
||||||
s.push_str("(");
|
|
||||||
for i in 0..nargs - 1 {
|
|
||||||
if i > 0 {
|
|
||||||
drop(write!(s, ", "));
|
|
||||||
}
|
|
||||||
drop(write!(s, "x{}", i));
|
|
||||||
}
|
|
||||||
s.push_str(");\n}");
|
|
||||||
s
|
|
||||||
}
|
|
||||||
shared::OperationKind::Getter(g) => format!(
|
|
||||||
"function() {{
|
|
||||||
return {}.{};
|
|
||||||
}}",
|
|
||||||
location, g
|
|
||||||
),
|
|
||||||
shared::OperationKind::Setter(s) => format!(
|
|
||||||
"function(y) {{
|
|
||||||
{}.{} = y;
|
|
||||||
}}",
|
|
||||||
location, s
|
|
||||||
),
|
|
||||||
shared::OperationKind::IndexingGetter => format!(
|
|
||||||
"function(y) {{
|
|
||||||
return {}[y];
|
|
||||||
}}",
|
|
||||||
location
|
|
||||||
),
|
|
||||||
shared::OperationKind::IndexingSetter => format!(
|
|
||||||
"function(y, z) {{
|
|
||||||
{}[y] = z;
|
|
||||||
}}",
|
|
||||||
location
|
|
||||||
),
|
|
||||||
shared::OperationKind::IndexingDeleter => format!(
|
|
||||||
"function(y) {{
|
|
||||||
delete {}[y];
|
|
||||||
}}",
|
|
||||||
location
|
|
||||||
),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let (location, binding) = if *is_static {
|
|
||||||
("", format!(".bind({})", class))
|
|
||||||
} else {
|
|
||||||
(".prototype", "".into())
|
|
||||||
};
|
|
||||||
|
|
||||||
match kind {
|
fn generated_import_target(
|
||||||
shared::OperationKind::Regular => {
|
&mut self,
|
||||||
format!("{}{}.{}{}", class, location, import.function.name, binding)
|
info: &shared::Import,
|
||||||
}
|
import: &shared::ImportFunction,
|
||||||
shared::OperationKind::Getter(g) => {
|
descriptor: &Descriptor,
|
||||||
self.cx.expose_get_inherited_descriptor();
|
) -> Result<String, Error> {
|
||||||
format!(
|
let method_data = match &import.method {
|
||||||
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').get{}",
|
Some(data) => data,
|
||||||
class, location, g, binding,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
shared::OperationKind::Setter(s) => {
|
|
||||||
self.cx.expose_get_inherited_descriptor();
|
|
||||||
format!(
|
|
||||||
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').set{}",
|
|
||||||
class, location, s, binding,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
shared::OperationKind::IndexingGetter => panic!("indexing getter should be structural"),
|
|
||||||
shared::OperationKind::IndexingSetter => panic!("indexing setter should be structural"),
|
|
||||||
shared::OperationKind::IndexingDeleter => panic!("indexing deleter should be structural"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let fallback = if import.structural {
|
|
||||||
"".to_string()
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
" || function() {{
|
|
||||||
throw new Error(`wasm-bindgen: {} does not exist`);
|
|
||||||
}}",
|
|
||||||
target
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.cx.global(&format!(
|
|
||||||
"
|
|
||||||
const {}_target = {} {} ;
|
|
||||||
",
|
|
||||||
import.shim, target, fallback
|
|
||||||
));
|
|
||||||
format!(
|
|
||||||
"{}_target{}",
|
|
||||||
import.shim,
|
|
||||||
if *is_static { "" } else { ".call" }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
None => {
|
||||||
let name = self.import_name(info, &import.function.name)?;
|
let name = self.import_name(info, &import.function.name)?;
|
||||||
if name.contains(".") {
|
return Ok(if name.contains(".") {
|
||||||
self.cx.global(&format!(
|
self.cx.global(&format!(
|
||||||
"
|
"
|
||||||
const {}_target = {};
|
const {}_target = {};
|
||||||
@ -1934,17 +1989,146 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
|||||||
format!("{}_target", import.shim)
|
format!("{}_target", import.shim)
|
||||||
} else {
|
} else {
|
||||||
name
|
name
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let js = Rust2Js::new(self.cx)
|
let class = match &method_data.class {
|
||||||
.catch(import.catch)
|
Some(class) => self.import_name(info, class)?,
|
||||||
.variadic(import.variadic)
|
None => {
|
||||||
.process(descriptor.unwrap_function())?
|
let op = match &method_data.kind {
|
||||||
.finish(&target);
|
shared::MethodKind::Operation(op) => op,
|
||||||
self.cx.export(&import.shim, &js, None);
|
shared::MethodKind::Constructor => {
|
||||||
Ok(())
|
bail!("\"no class\" methods cannot be constructors")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match &op.kind {
|
||||||
|
shared::OperationKind::Regular => {
|
||||||
|
return Ok(import.function.name.to_string())
|
||||||
|
}
|
||||||
|
shared::OperationKind::Getter(g) => {
|
||||||
|
return Ok(format!("(() => {})", g));
|
||||||
|
}
|
||||||
|
shared::OperationKind::Setter(g) => {
|
||||||
|
return Ok(format!("(v => {} = v)", g));
|
||||||
|
}
|
||||||
|
_ => bail!("\"no class\" methods must be regular/getter/setter"),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let op = match &method_data.kind {
|
||||||
|
shared::MethodKind::Constructor => return Ok(format!("new {}", class)),
|
||||||
|
shared::MethodKind::Operation(op) => op,
|
||||||
|
};
|
||||||
|
let target = if import.structural {
|
||||||
|
let location = if op.is_static { &class } else { "this" };
|
||||||
|
|
||||||
|
match &op.kind {
|
||||||
|
shared::OperationKind::Regular => {
|
||||||
|
let nargs = descriptor.unwrap_function().arguments.len();
|
||||||
|
let mut s = format!("function(");
|
||||||
|
for i in 0..nargs - 1 {
|
||||||
|
if i > 0 {
|
||||||
|
drop(write!(s, ", "));
|
||||||
|
}
|
||||||
|
drop(write!(s, "x{}", i));
|
||||||
|
}
|
||||||
|
s.push_str(") { \nreturn this.");
|
||||||
|
s.push_str(&import.function.name);
|
||||||
|
s.push_str("(");
|
||||||
|
for i in 0..nargs - 1 {
|
||||||
|
if i > 0 {
|
||||||
|
drop(write!(s, ", "));
|
||||||
|
}
|
||||||
|
drop(write!(s, "x{}", i));
|
||||||
|
}
|
||||||
|
s.push_str(");\n}");
|
||||||
|
s
|
||||||
|
}
|
||||||
|
shared::OperationKind::Getter(g) => format!(
|
||||||
|
"function() {{
|
||||||
|
return {}.{};
|
||||||
|
}}",
|
||||||
|
location, g
|
||||||
|
),
|
||||||
|
shared::OperationKind::Setter(s) => format!(
|
||||||
|
"function(y) {{
|
||||||
|
{}.{} = y;
|
||||||
|
}}",
|
||||||
|
location, s
|
||||||
|
),
|
||||||
|
shared::OperationKind::IndexingGetter => format!(
|
||||||
|
"function(y) {{
|
||||||
|
return {}[y];
|
||||||
|
}}",
|
||||||
|
location
|
||||||
|
),
|
||||||
|
shared::OperationKind::IndexingSetter => format!(
|
||||||
|
"function(y, z) {{
|
||||||
|
{}[y] = z;
|
||||||
|
}}",
|
||||||
|
location
|
||||||
|
),
|
||||||
|
shared::OperationKind::IndexingDeleter => format!(
|
||||||
|
"function(y) {{
|
||||||
|
delete {}[y];
|
||||||
|
}}",
|
||||||
|
location
|
||||||
|
),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (location, binding) = if op.is_static {
|
||||||
|
("", format!(".bind({})", class))
|
||||||
|
} else {
|
||||||
|
(".prototype", "".into())
|
||||||
|
};
|
||||||
|
|
||||||
|
match &op.kind {
|
||||||
|
shared::OperationKind::Regular => {
|
||||||
|
format!("{}{}.{}{}", class, location, import.function.name, binding)
|
||||||
|
}
|
||||||
|
shared::OperationKind::Getter(g) => {
|
||||||
|
self.cx.expose_get_inherited_descriptor();
|
||||||
|
format!(
|
||||||
|
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').get{}",
|
||||||
|
class, location, g, binding,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
shared::OperationKind::Setter(s) => {
|
||||||
|
self.cx.expose_get_inherited_descriptor();
|
||||||
|
format!(
|
||||||
|
"GetOwnOrInheritedPropertyDescriptor({}{}, '{}').set{}",
|
||||||
|
class, location, s, binding,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
shared::OperationKind::IndexingGetter => panic!("indexing getter should be structural"),
|
||||||
|
shared::OperationKind::IndexingSetter => panic!("indexing setter should be structural"),
|
||||||
|
shared::OperationKind::IndexingDeleter => panic!("indexing deleter should be structural"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let fallback = if import.structural {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
format!(
|
||||||
|
" || function() {{
|
||||||
|
throw new Error(`wasm-bindgen: {} does not exist`);
|
||||||
|
}}",
|
||||||
|
target
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.cx.global(&format!(
|
||||||
|
"const {}_target = {}{};",
|
||||||
|
import.shim, target, fallback
|
||||||
|
));
|
||||||
|
Ok(format!(
|
||||||
|
"{}_target{}",
|
||||||
|
import.shim,
|
||||||
|
if op.is_static { "" } else { ".call" }
|
||||||
|
))
|
||||||
|
>>>>>>> master
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_import_type(
|
fn generate_import_type(
|
||||||
|
@ -4,13 +4,13 @@ extern crate parity_wasm;
|
|||||||
extern crate wasm_bindgen_shared as shared;
|
extern crate wasm_bindgen_shared as shared;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate wasm_gc;
|
extern crate wasm_gc;
|
||||||
extern crate wasmi;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
|
extern crate wasm_bindgen_wasm_interpreter as wasm_interpreter;
|
||||||
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@ -33,6 +33,9 @@ pub struct Bindgen {
|
|||||||
typescript: bool,
|
typescript: bool,
|
||||||
demangle: bool,
|
demangle: bool,
|
||||||
keep_debug: bool,
|
keep_debug: bool,
|
||||||
|
// Experimental support for `WeakRefGroup`, an upcoming ECMAScript feature.
|
||||||
|
// Currently only enable-able through an env var.
|
||||||
|
weak_refs: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Input {
|
enum Input {
|
||||||
@ -55,6 +58,7 @@ impl Bindgen {
|
|||||||
typescript: false,
|
typescript: false,
|
||||||
demangle: true,
|
demangle: true,
|
||||||
keep_debug: false,
|
keep_debug: false,
|
||||||
|
weak_refs: env::var("WASM_BINDGEN_WEAKREF").is_ok(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,13 +183,7 @@ impl Bindgen {
|
|||||||
// This means that whenever we encounter an import or export we'll
|
// This means that whenever we encounter an import or export we'll
|
||||||
// execute a shim function which informs us about its type so we can
|
// execute a shim function which informs us about its type so we can
|
||||||
// then generate the appropriate bindings.
|
// then generate the appropriate bindings.
|
||||||
//
|
let mut instance = wasm_interpreter::Interpreter::new(&module);
|
||||||
// TODO: avoid a `clone` here of the module if we can
|
|
||||||
let instance = wasmi::Module::from_parity_wasm_module(module.clone())
|
|
||||||
.with_context(|_| "failed to create wasmi module")?;
|
|
||||||
let instance = wasmi::ModuleInstance::new(&instance, &MyResolver)
|
|
||||||
.with_context(|_| "failed to instantiate wasm module")?;
|
|
||||||
let instance = instance.not_started_instance();
|
|
||||||
|
|
||||||
let (js, ts) = {
|
let (js, ts) = {
|
||||||
let mut cx = js::Context {
|
let mut cx = js::Context {
|
||||||
@ -201,20 +199,10 @@ impl Bindgen {
|
|||||||
config: &self,
|
config: &self,
|
||||||
module: &mut module,
|
module: &mut module,
|
||||||
function_table_needed: false,
|
function_table_needed: false,
|
||||||
run_descriptor: &|name| {
|
interpreter: &mut instance,
|
||||||
let mut v = MyExternals(Vec::new());
|
memory_init: None,
|
||||||
match instance.invoke_export(name, &[], &mut v) {
|
imported_functions: Default::default(),
|
||||||
Ok(None) => Some(v.0),
|
imported_statics: Default::default(),
|
||||||
Ok(Some(_)) => unreachable!(
|
|
||||||
"there is only one export, and we only return None from it"
|
|
||||||
),
|
|
||||||
// Allow missing exported describe functions. This can
|
|
||||||
// happen when a nested dependency crate exports things
|
|
||||||
// but the root crate doesn't use them.
|
|
||||||
Err(wasmi::Error::Function(_)) => None,
|
|
||||||
Err(e) => panic!("unexpected error running descriptor: {}", e),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
for program in programs.iter() {
|
for program in programs.iter() {
|
||||||
js::SubContext {
|
js::SubContext {
|
||||||
@ -336,7 +324,6 @@ fn extract_programs(module: &mut Module) -> Result<Vec<shared::Program>, Error>
|
|||||||
to_remove.push(i);
|
to_remove.push(i);
|
||||||
|
|
||||||
let mut payload = custom.payload();
|
let mut payload = custom.payload();
|
||||||
let mut added_programs = Vec::new();
|
|
||||||
while payload.len() > 0 {
|
while payload.len() > 0 {
|
||||||
let len = ((payload[0] as usize) << 0)
|
let len = ((payload[0] as usize) << 0)
|
||||||
| ((payload[1] as usize) << 8)
|
| ((payload[1] as usize) << 8)
|
||||||
@ -345,19 +332,6 @@ fn extract_programs(module: &mut Module) -> Result<Vec<shared::Program>, Error>
|
|||||||
let (a, b) = payload[4..].split_at(len as usize);
|
let (a, b) = payload[4..].split_at(len as usize);
|
||||||
payload = b;
|
payload = b;
|
||||||
|
|
||||||
// Due to a nasty LLVM bug it's currently possible for LLVM to
|
|
||||||
// duplicate custom section directives in intermediate object files.
|
|
||||||
// This means that we could see multiple program directives when in
|
|
||||||
// fact we were originally only meant to see one!
|
|
||||||
//
|
|
||||||
// Work around the issue here until the upstream bug,
|
|
||||||
// https://bugs.llvm.org/show_bug.cgi?id=38184, is hopefully fixed
|
|
||||||
// via some other means.
|
|
||||||
if added_programs.iter().any(|p| a == *p) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
added_programs.push(a);
|
|
||||||
|
|
||||||
let p: shared::ProgramOnlySchema = match serde_json::from_slice(&a) {
|
let p: shared::ProgramOnlySchema = match serde_json::from_slice(&a) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => bail!("failed to decode what looked like wasm-bindgen data: {}", e),
|
Err(e) => bail!("failed to decode what looked like wasm-bindgen data: {}", e),
|
||||||
@ -404,106 +378,6 @@ to open an issue at https://github.com/rustwasm/wasm-bindgen/issues!
|
|||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyResolver;
|
|
||||||
|
|
||||||
impl wasmi::ImportResolver for MyResolver {
|
|
||||||
fn resolve_func(
|
|
||||||
&self,
|
|
||||||
module_name: &str,
|
|
||||||
field_name: &str,
|
|
||||||
signature: &wasmi::Signature,
|
|
||||||
) -> Result<wasmi::FuncRef, wasmi::Error> {
|
|
||||||
// Route our special "describe" export to 1 and everything else to 0.
|
|
||||||
// That way whenever the function 1 is invoked we know what to do and
|
|
||||||
// when 0 is invoked (by accident) we'll trap and produce an error.
|
|
||||||
let idx = (module_name == "__wbindgen_placeholder__" && field_name == "__wbindgen_describe")
|
|
||||||
as usize;
|
|
||||||
Ok(wasmi::FuncInstance::alloc_host(signature.clone(), idx))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_global(
|
|
||||||
&self,
|
|
||||||
_module_name: &str,
|
|
||||||
_field_name: &str,
|
|
||||||
descriptor: &wasmi::GlobalDescriptor,
|
|
||||||
) -> Result<wasmi::GlobalRef, wasmi::Error> {
|
|
||||||
// dummy implementation to ensure instantiation succeeds
|
|
||||||
let val = match descriptor.value_type() {
|
|
||||||
wasmi::ValueType::I32 => wasmi::RuntimeValue::I32(0),
|
|
||||||
wasmi::ValueType::I64 => wasmi::RuntimeValue::I64(0),
|
|
||||||
wasmi::ValueType::F32 => wasmi::RuntimeValue::F32(0.0.into()),
|
|
||||||
wasmi::ValueType::F64 => wasmi::RuntimeValue::F64(0.0.into()),
|
|
||||||
};
|
|
||||||
Ok(wasmi::GlobalInstance::alloc(val, descriptor.is_mutable()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_memory(
|
|
||||||
&self,
|
|
||||||
_module_name: &str,
|
|
||||||
_field_name: &str,
|
|
||||||
descriptor: &wasmi::MemoryDescriptor,
|
|
||||||
) -> Result<wasmi::MemoryRef, wasmi::Error> {
|
|
||||||
// dummy implementation to ensure instantiation succeeds
|
|
||||||
use wasmi::memory_units::Pages;
|
|
||||||
let initial = Pages(descriptor.initial() as usize);
|
|
||||||
let maximum = descriptor.maximum().map(|i| Pages(i as usize));
|
|
||||||
wasmi::MemoryInstance::alloc(initial, maximum)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_table(
|
|
||||||
&self,
|
|
||||||
_module_name: &str,
|
|
||||||
_field_name: &str,
|
|
||||||
descriptor: &wasmi::TableDescriptor,
|
|
||||||
) -> Result<wasmi::TableRef, wasmi::Error> {
|
|
||||||
// dummy implementation to ensure instantiation succeeds
|
|
||||||
let initial = descriptor.initial();
|
|
||||||
let maximum = descriptor.maximum();
|
|
||||||
wasmi::TableInstance::alloc(initial, maximum)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MyExternals(Vec<u32>);
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct MyError(String);
|
|
||||||
|
|
||||||
impl wasmi::Externals for MyExternals {
|
|
||||||
fn invoke_index(
|
|
||||||
&mut self,
|
|
||||||
index: usize,
|
|
||||||
args: wasmi::RuntimeArgs,
|
|
||||||
) -> Result<Option<wasmi::RuntimeValue>, wasmi::Trap> {
|
|
||||||
macro_rules! bail {
|
|
||||||
($($t:tt)*) => ({
|
|
||||||
let s = MyError(format!($($t)*));
|
|
||||||
return Err(wasmi::Trap::new(wasmi::TrapKind::Host(Box::new(s))))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// We only recognize one function here which was mapped to the index 1
|
|
||||||
// by the resolver above.
|
|
||||||
if index != 1 {
|
|
||||||
bail!("only __wbindgen_describe can be run at this time")
|
|
||||||
}
|
|
||||||
if args.len() != 1 {
|
|
||||||
bail!("must have exactly one argument");
|
|
||||||
}
|
|
||||||
match args.nth_value_checked(0)? {
|
|
||||||
wasmi::RuntimeValue::I32(i) => self.0.push(i as u32),
|
|
||||||
_ => bail!("expected one argument of i32 type"),
|
|
||||||
}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl wasmi::HostError for MyError {}
|
|
||||||
|
|
||||||
impl fmt::Display for MyError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_indentation(s: &str) -> String {
|
fn reset_indentation(s: &str) -> String {
|
||||||
let mut indent: u32 = 0;
|
let mut indent: u32 = 0;
|
||||||
let mut dst = String::new();
|
let mut dst = String::new();
|
||||||
|
@ -150,19 +150,6 @@ impl Output {
|
|||||||
if let Some(i) = self.module.import_section() {
|
if let Some(i) = self.module.import_section() {
|
||||||
let mut set = HashSet::new();
|
let mut set = HashSet::new();
|
||||||
for entry in i.entries() {
|
for entry in i.entries() {
|
||||||
match *entry.external() {
|
|
||||||
External::Function(_) => {}
|
|
||||||
External::Table(_) => {
|
|
||||||
bail!("wasm imports a table which isn't supported yet");
|
|
||||||
}
|
|
||||||
External::Memory(_) => {
|
|
||||||
bail!("wasm imports memory which isn't supported yet");
|
|
||||||
}
|
|
||||||
External::Global(_) => {
|
|
||||||
bail!("wasm imports globals which aren't supported yet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !set.insert(entry.module()) {
|
if !set.insert(entry.module()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-cli"
|
name = "wasm-bindgen-cli"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli"
|
||||||
@ -18,13 +18,13 @@ docopt = "1.0"
|
|||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
failure = "0.1.2"
|
failure = "0.1.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
parity-wasm = "0.31"
|
parity-wasm = "0.32"
|
||||||
rouille = { version = "2.1.0", default-features = false }
|
rouille = { version = "2.1.0", default-features = false }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.17" }
|
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.19" }
|
||||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.17" }
|
wasm-bindgen-shared = { path = "../shared", version = "=0.2.19" }
|
||||||
openssl = { version = '0.10.11', optional = true }
|
openssl = { version = '0.10.11', optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -7,12 +7,12 @@ license = "MIT/Apache-2.0"
|
|||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures"
|
||||||
readme = "./README.md"
|
readme = "./README.md"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
futures = "0.1.20"
|
futures = "0.1.20"
|
||||||
js-sys = { path = "../js-sys", version = '0.2.1' }
|
js-sys = { path = "../js-sys", version = '0.2.4' }
|
||||||
wasm-bindgen = { path = "../..", version = '0.2.17' }
|
wasm-bindgen = { path = "../..", version = '0.2.19' }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
wasm-bindgen-test = { path = '../test', version = '0.2.17' }
|
wasm-bindgen-test = { path = '../test', version = '0.2.19' }
|
||||||
|
@ -33,8 +33,6 @@
|
|||||||
//! `Promise`.
|
//! `Promise`.
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! #![feature(use_extern_macros)]
|
|
||||||
//!
|
|
||||||
//! extern crate futures;
|
//! extern crate futures;
|
||||||
//! extern crate js_sys;
|
//! extern crate js_sys;
|
||||||
//! extern crate wasm_bindgen;
|
//! extern crate wasm_bindgen;
|
||||||
@ -104,7 +102,6 @@
|
|||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
#![cfg(target_arch = "wasm32")]
|
#![cfg(target_arch = "wasm32")]
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.2.2"
|
version = "0.2.4"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
readme = "./README.md"
|
readme = "./README.md"
|
||||||
categories = ["wasm"]
|
categories = ["wasm"]
|
||||||
@ -18,7 +18,9 @@ test = false
|
|||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = { path = "../..", version = "0.2.17" }
|
wasm-bindgen = { path = "../..", version = "0.2.19" }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
wasm-bindgen-test = { path = '../test', version = '=0.2.17' }
|
futures = "0.1.20"
|
||||||
|
wasm-bindgen-test = { path = '../test', version = '=0.2.19' }
|
||||||
|
wasm-bindgen-futures = { path = '../futures', version = '=0.2.19' }
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
#![cfg(target_arch = "wasm32")]
|
#![cfg(target_arch = "wasm32")]
|
||||||
|
|
||||||
extern crate wasm_bindgen_test;
|
extern crate wasm_bindgen_test;
|
||||||
|
@ -306,4 +306,5 @@ fn array_inheritance() {
|
|||||||
let array = Array::new();
|
let array = Array::new();
|
||||||
assert!(array.is_instance_of::<Array>());
|
assert!(array.is_instance_of::<Array>());
|
||||||
assert!(array.is_instance_of::<Object>());
|
assert!(array.is_instance_of::<Object>());
|
||||||
|
let _: &Object = array.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -41,4 +41,5 @@ fn arraybuffer_inheritance() {
|
|||||||
let buf = ArrayBuffer::new(4);
|
let buf = ArrayBuffer::new(4);
|
||||||
assert!(buf.is_instance_of::<ArrayBuffer>());
|
assert!(buf.is_instance_of::<ArrayBuffer>());
|
||||||
assert!(buf.is_instance_of::<Object>());
|
assert!(buf.is_instance_of::<Object>());
|
||||||
|
let _: &Object = buf.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -18,4 +18,5 @@ fn boolean_inheritance() {
|
|||||||
let b = Boolean::new(&JsValue::from(true));
|
let b = Boolean::new(&JsValue::from(true));
|
||||||
assert!(b.is_instance_of::<Boolean>());
|
assert!(b.is_instance_of::<Boolean>());
|
||||||
assert!(b.is_instance_of::<Object>());
|
assert!(b.is_instance_of::<Object>());
|
||||||
|
let _: &Object = b.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
use js_sys::*;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
use wasm_bindgen::JsCast;
|
|
||||||
use js_sys::*;
|
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test() {
|
fn test() {
|
||||||
@ -36,7 +36,9 @@ fn test() {
|
|||||||
v.set_int8(0, 42);
|
v.set_int8(0, 42);
|
||||||
|
|
||||||
// TODO: figure out how to do `bytes[2]`
|
// TODO: figure out how to do `bytes[2]`
|
||||||
bytes.subarray(2, 3).for_each(&mut |x, _, _| assert_eq!(x, 42));
|
bytes
|
||||||
|
.subarray(2, 3)
|
||||||
|
.for_each(&mut |x, _, _| assert_eq!(x, 42));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
@ -50,4 +52,5 @@ fn dataview_inheritance() {
|
|||||||
|
|
||||||
assert!(v.is_instance_of::<DataView>());
|
assert!(v.is_instance_of::<DataView>());
|
||||||
assert!(v.is_instance_of::<Object>());
|
assert!(v.is_instance_of::<Object>());
|
||||||
|
let _: &Object = v.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -413,4 +413,5 @@ fn date_inheritance() {
|
|||||||
let date = Date::new(&"August 19, 1975 23:15:30".into());
|
let date = Date::new(&"August 19, 1975 23:15:30".into());
|
||||||
assert!(date.is_instance_of::<Date>());
|
assert!(date.is_instance_of::<Date>());
|
||||||
assert!(date.is_instance_of::<Object>());
|
assert!(date.is_instance_of::<Object>());
|
||||||
|
let _: &Object = date.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -42,4 +42,5 @@ fn error_inheritance() {
|
|||||||
let error = Error::new("test");
|
let error = Error::new("test");
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -52,4 +52,6 @@ fn evalerror_inheritance() {
|
|||||||
assert!(error.is_instance_of::<EvalError>());
|
assert!(error.is_instance_of::<EvalError>());
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -66,4 +66,5 @@ fn to_string() {
|
|||||||
fn function_inheritance() {
|
fn function_inheritance() {
|
||||||
assert!(MAX.is_instance_of::<Function>());
|
assert!(MAX.is_instance_of::<Function>());
|
||||||
assert!(MAX.is_instance_of::<Object>());
|
assert!(MAX.is_instance_of::<Object>());
|
||||||
|
let _: &Object = MAX.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
use js_sys::*;
|
use js_sys::*;
|
||||||
|
|
||||||
#[wasm_bindgen(module = "tests/wasm/Generator.js")]
|
#[wasm_bindgen(module = "tests/wasm/Generator.js")]
|
||||||
@ -56,3 +57,10 @@ fn throw() {
|
|||||||
assert!(next.value().is_undefined());
|
assert!(next.value().is_undefined());
|
||||||
assert!(next.done());
|
assert!(next.done());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn generator_inheritance() {
|
||||||
|
let gen = dummy_generator();
|
||||||
|
|
||||||
|
assert!(gen.is_instance_of::<Object>());
|
||||||
|
}
|
||||||
|
@ -37,6 +37,17 @@ fn collator() {
|
|||||||
assert!(a.is_instance_of::<Array>());
|
assert!(a.is_instance_of::<Array>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn collator_inheritance() {
|
||||||
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
|
let opts = Object::new();
|
||||||
|
let c = Intl::Collator::new(&locales, &opts);
|
||||||
|
|
||||||
|
assert!(c.is_instance_of::<Intl::Collator>());
|
||||||
|
assert!(c.is_instance_of::<Object>());
|
||||||
|
let _: &Object = c.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn date_time_format() {
|
fn date_time_format() {
|
||||||
let locales = Array::of1(&JsValue::from("en-US"));
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
@ -52,6 +63,17 @@ fn date_time_format() {
|
|||||||
assert!(a.is_instance_of::<Array>());
|
assert!(a.is_instance_of::<Array>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn date_time_format_inheritance() {
|
||||||
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
|
let opts = Object::new();
|
||||||
|
let c = Intl::DateTimeFormat::new(&locales, &opts);
|
||||||
|
|
||||||
|
assert!(c.is_instance_of::<Intl::DateTimeFormat>());
|
||||||
|
assert!(c.is_instance_of::<Object>());
|
||||||
|
let _: &Object = c.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn number_format() {
|
fn number_format() {
|
||||||
let locales = Array::of1(&JsValue::from("en-US"));
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
@ -66,6 +88,17 @@ fn number_format() {
|
|||||||
assert!(a.is_instance_of::<Array>());
|
assert!(a.is_instance_of::<Array>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn number_format_inheritance() {
|
||||||
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
|
let opts = Object::new();
|
||||||
|
let n = Intl::NumberFormat::new(&locales, &opts);
|
||||||
|
|
||||||
|
assert!(n.is_instance_of::<Intl::NumberFormat>());
|
||||||
|
assert!(n.is_instance_of::<Object>());
|
||||||
|
let _: &Object = n.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn plural_rules() {
|
fn plural_rules() {
|
||||||
let locales = Array::of1(&JsValue::from("en-US"));
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
@ -75,6 +108,17 @@ fn plural_rules() {
|
|||||||
assert!(r.resolved_options().is_instance_of::<Object>());
|
assert!(r.resolved_options().is_instance_of::<Object>());
|
||||||
assert_eq!(r.select(1_f64), "one");
|
assert_eq!(r.select(1_f64), "one");
|
||||||
|
|
||||||
let r = Intl::PluralRules::supported_locales_of(&locales, &opts);
|
let a = Intl::PluralRules::supported_locales_of(&locales, &opts);
|
||||||
assert!(r.is_instance_of::<Array>());
|
assert!(a.is_instance_of::<Array>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn plural_rules_inheritance() {
|
||||||
|
let locales = Array::of1(&JsValue::from("en-US"));
|
||||||
|
let opts = Object::new();
|
||||||
|
let r = Intl::PluralRules::new(&locales, &opts);
|
||||||
|
|
||||||
|
assert!(r.is_instance_of::<Intl::PluralRules>());
|
||||||
|
assert!(r.is_instance_of::<Object>());
|
||||||
|
let _: &Object = r.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -1 +1,7 @@
|
|||||||
exports.new_string_object = () => new String("hi");
|
exports.new_string_object = () => new String("hi");
|
||||||
|
|
||||||
|
exports.get_replacer_function = function() {
|
||||||
|
return function upperToHyphenLower(match, offset, string) {
|
||||||
|
return (offset > 0 ? '-' : '') + match.toLowerCase();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -7,6 +7,7 @@ use js_sys::*;
|
|||||||
#[wasm_bindgen(module = "tests/wasm/JsString.js")]
|
#[wasm_bindgen(module = "tests/wasm/JsString.js")]
|
||||||
extern {
|
extern {
|
||||||
fn new_string_object() -> JsValue;
|
fn new_string_object() -> JsValue;
|
||||||
|
fn get_replacer_function() -> Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
@ -85,6 +86,23 @@ fn from_char_code() {
|
|||||||
assert_eq!(JsString::from_char_code4(codes[0], codes[1], codes[2], codes[3]), "½+¾=");
|
assert_eq!(JsString::from_char_code4(codes[0], codes[1], codes[2], codes[3]), "½+¾=");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn from_code_point() {
|
||||||
|
let s = "☃★♲你";
|
||||||
|
let codes : Vec<u32> = s.chars()
|
||||||
|
.map(|char| char as u32)
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(JsString::from_code_point1(codes[0]).unwrap(), "☃");
|
||||||
|
assert_eq!(JsString::from_code_point2(codes[0], codes[1]).unwrap(), "☃★");
|
||||||
|
assert_eq!(JsString::from_code_point3(codes[0], codes[1], codes[2]).unwrap(), "☃★♲");
|
||||||
|
assert_eq!(JsString::from_code_point4(codes[0], codes[1], codes[2], codes[3]).unwrap(), "☃★♲你");
|
||||||
|
|
||||||
|
assert!(!JsString::from_code_point1(0x10FFFF).is_err());
|
||||||
|
assert!(JsString::from_code_point1(0x110000).is_err());
|
||||||
|
assert!(JsString::from_code_point1(u32::max_value()).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn includes() {
|
fn includes() {
|
||||||
let str = JsString::from("Blue Whale");
|
let str = JsString::from("Blue Whale");
|
||||||
@ -135,6 +153,95 @@ fn last_index_of() {
|
|||||||
assert_eq!(js.last_index_of("", 2), 2);
|
assert_eq!(js.last_index_of("", 2), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn locale_compare() {
|
||||||
|
let a = "résumé";
|
||||||
|
let b = "RESUME";
|
||||||
|
let js_a = JsString::from(a);
|
||||||
|
let js_b = JsString::from(b);
|
||||||
|
let locales = Array::new();
|
||||||
|
let options = Object::new();
|
||||||
|
|
||||||
|
assert_eq!(js_a.locale_compare(a, &locales, &options), 0);
|
||||||
|
assert_eq!(js_b.locale_compare(b, &locales, &options), 0);
|
||||||
|
assert!(js_a.locale_compare(b, &locales, &options) > 0);
|
||||||
|
assert!(js_b.locale_compare(a, &locales, &options) < 0);
|
||||||
|
|
||||||
|
locales.push(&"en".into());
|
||||||
|
Reflect::set(options.as_ref(), &"sensitivity".into(), &"base".into());
|
||||||
|
|
||||||
|
assert_eq!(js_a.locale_compare(a, &locales, &options), 0);
|
||||||
|
assert_eq!(js_a.locale_compare(b, &locales, &options), 0);
|
||||||
|
assert_eq!(js_b.locale_compare(a, &locales, &options), 0);
|
||||||
|
assert_eq!(js_b.locale_compare(b, &locales, &options), 0);
|
||||||
|
|
||||||
|
let a = "ä";
|
||||||
|
let z = "z";
|
||||||
|
let js_a = JsString::from(a);
|
||||||
|
let js_z = JsString::from(z);
|
||||||
|
let locales_de = Array::of1(&"de".into());
|
||||||
|
let locales_sv = Array::of1(&"sv".into());
|
||||||
|
let options = Object::new();
|
||||||
|
|
||||||
|
assert_eq!(js_a.locale_compare(a, &locales_de, &options), 0);
|
||||||
|
assert_eq!(js_z.locale_compare(z, &locales_de, &options), 0);
|
||||||
|
assert!(js_a.locale_compare(z, &locales_de, &options) < 0);
|
||||||
|
assert!(js_z.locale_compare(a, &locales_de, &options) > 0);
|
||||||
|
|
||||||
|
assert_eq!(js_a.locale_compare(a, &locales_sv, &options), 0);
|
||||||
|
assert_eq!(js_z.locale_compare(z, &locales_sv, &options), 0);
|
||||||
|
assert!(js_a.locale_compare(z, &locales_sv, &options) < 0);
|
||||||
|
assert!(js_z.locale_compare(a, &locales_sv, &options) > 0);
|
||||||
|
|
||||||
|
let two = "2";
|
||||||
|
let ten = "10";
|
||||||
|
let js_two = JsString::from(two);
|
||||||
|
let js_ten = JsString::from(ten);
|
||||||
|
let locales = Array::new();
|
||||||
|
let options = Object::new();
|
||||||
|
|
||||||
|
assert_eq!(js_two.locale_compare(two, &locales, &options), 0);
|
||||||
|
assert_eq!(js_ten.locale_compare(ten, &locales, &options), 0);
|
||||||
|
assert!(js_two.locale_compare(ten, &locales, &options) > 0);
|
||||||
|
assert!(js_ten.locale_compare(two, &locales, &options) < 0);
|
||||||
|
|
||||||
|
locales.push(&"en-u-kn-true".into());
|
||||||
|
|
||||||
|
assert!(js_two.locale_compare(ten, &locales, &options) < 0);
|
||||||
|
assert!(js_ten.locale_compare(two, &locales, &options) > 0);
|
||||||
|
|
||||||
|
let locales = Array::new();
|
||||||
|
Reflect::set(options.as_ref(), &"numeric".into(), &JsValue::TRUE);
|
||||||
|
|
||||||
|
assert!(js_two.locale_compare(ten, &locales, &options) < 0);
|
||||||
|
assert!(js_ten.locale_compare(two, &locales, &options) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn match_() {
|
||||||
|
let s = "The quick brown fox jumped over the lazy dog. It barked.";
|
||||||
|
let re = RegExp::new("[A-Z]", "g");
|
||||||
|
let result = JsString::from(s).match_(&re);
|
||||||
|
let obj = result.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"0".into()), "T");
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"1".into()), "I");
|
||||||
|
|
||||||
|
let result = JsString::from("foo").match_(&re);
|
||||||
|
assert!(result.is_none());
|
||||||
|
|
||||||
|
let s = "For more information, see Chapter 3.4.5.1";
|
||||||
|
let re = RegExp::new("see (chapter \\d+(\\.\\d)*)", "i");
|
||||||
|
let result = JsString::from(s).match_(&re);
|
||||||
|
let obj = result.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"0".into()), "see Chapter 3.4.5.1");
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"1".into()), "Chapter 3.4.5.1");
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"2".into()), ".1");
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"index".into()), 22);
|
||||||
|
assert_eq!(Reflect::get(obj.as_ref(), &"input".into()), s);
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn normalize() {
|
fn normalize() {
|
||||||
let js = JsString::from("\u{1E9B}\u{0323}");
|
let js = JsString::from("\u{1E9B}\u{0323}");
|
||||||
@ -178,12 +285,106 @@ fn repeat() {
|
|||||||
assert_eq!(JsString::from("test").repeat(3), "testtesttest");
|
assert_eq!(JsString::from("test").repeat(3), "testtesttest");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn replace() {
|
||||||
|
let js = JsString::from("The quick brown fox jumped over the lazy dog. If the dog reacted, was it really lazy?");
|
||||||
|
let result = js.replace("dog", "ferret");
|
||||||
|
|
||||||
|
assert_eq!(result, "The quick brown fox jumped over the lazy ferret. If the dog reacted, was it really lazy?");
|
||||||
|
|
||||||
|
let js = JsString::from("borderTop");
|
||||||
|
let result = js.replace_with_function("T", &get_replacer_function());
|
||||||
|
|
||||||
|
assert_eq!(result, "border-top");
|
||||||
|
|
||||||
|
let js = JsString::from("The quick brown fox jumped over the lazy dog. If the dog reacted, was it really lazy?");
|
||||||
|
let re = RegExp::new("dog", "g");
|
||||||
|
let result = js.replace_by_pattern(&re, "ferret");
|
||||||
|
|
||||||
|
assert_eq!(result, "The quick brown fox jumped over the lazy ferret. If the ferret reacted, was it really lazy?");
|
||||||
|
|
||||||
|
let js = JsString::from("borderTop");
|
||||||
|
let re = RegExp::new("[A-Z]", "g");
|
||||||
|
let result = js.replace_by_pattern_with_function(&re, &get_replacer_function());
|
||||||
|
|
||||||
|
assert_eq!(result, "border-top");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn search() {
|
||||||
|
let js = JsString::from("The quick brown fox jumped over the lazy dog. If the dog reacted, was it really lazy?");
|
||||||
|
let re = RegExp::new("[^\\w\\s]", "g");
|
||||||
|
|
||||||
|
assert_eq!(js.search(&re), 44);
|
||||||
|
|
||||||
|
let js = JsString::from("hey JudE");
|
||||||
|
let re1 = RegExp::new("[A-Z]", "g");
|
||||||
|
let re2 = RegExp::new("[.]", "g");
|
||||||
|
|
||||||
|
assert_eq!(js.search(&re1), 4);
|
||||||
|
assert_eq!(js.search(&re2), -1);
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn slice() {
|
fn slice() {
|
||||||
let characters = JsString::from("acxn18");
|
let characters = JsString::from("acxn18");
|
||||||
assert_eq!(characters.slice(1, 3), "cx");
|
assert_eq!(characters.slice(1, 3), "cx");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn split() {
|
||||||
|
let js = JsString::from("Oh brave new world");
|
||||||
|
let result = js.split(" ");
|
||||||
|
|
||||||
|
let mut v = Vec::with_capacity(result.length() as usize);
|
||||||
|
result.for_each(&mut |x, _, _| v.push(x));
|
||||||
|
|
||||||
|
assert_eq!(v[0], "Oh");
|
||||||
|
assert_eq!(v[1], "brave");
|
||||||
|
assert_eq!(v[2], "new");
|
||||||
|
assert_eq!(v[3], "world");
|
||||||
|
|
||||||
|
let js = JsString::from("Oct,Nov,Dec");
|
||||||
|
let result = js.split(",");
|
||||||
|
|
||||||
|
let mut v = Vec::with_capacity(result.length() as usize);
|
||||||
|
result.for_each(&mut |x, _, _| v.push(x));
|
||||||
|
|
||||||
|
assert_eq!(v[0], "Oct");
|
||||||
|
assert_eq!(v[1], "Nov");
|
||||||
|
assert_eq!(v[2], "Dec");
|
||||||
|
|
||||||
|
let result = js.split_limit(",", 2);
|
||||||
|
|
||||||
|
let mut v = Vec::with_capacity(result.length() as usize);
|
||||||
|
result.for_each(&mut |x, _, _| v.push(x));
|
||||||
|
|
||||||
|
assert_eq!(result.length(), 2);
|
||||||
|
assert_eq!(v[0], "Oct");
|
||||||
|
assert_eq!(v[1], "Nov");
|
||||||
|
|
||||||
|
let js = JsString::from("Oh brave new world");
|
||||||
|
let re = RegExp::new("\\s", "g");
|
||||||
|
let result = js.split_by_pattern(&re);
|
||||||
|
|
||||||
|
let mut v = Vec::with_capacity(result.length() as usize);
|
||||||
|
result.for_each(&mut |x, _, _| v.push(x));
|
||||||
|
|
||||||
|
assert_eq!(v[0], "Oh");
|
||||||
|
assert_eq!(v[1], "brave");
|
||||||
|
assert_eq!(v[2], "new");
|
||||||
|
assert_eq!(v[3], "world");
|
||||||
|
|
||||||
|
let result = js.split_by_pattern_limit(&re, 2);
|
||||||
|
|
||||||
|
let mut v = Vec::with_capacity(result.length() as usize);
|
||||||
|
result.for_each(&mut |x, _, _| v.push(x));
|
||||||
|
|
||||||
|
assert_eq!(result.length(), 2);
|
||||||
|
assert_eq!(v[0], "Oh");
|
||||||
|
assert_eq!(v[1], "brave");
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn starts_with() {
|
fn starts_with() {
|
||||||
let js = JsString::from("To be, or not to be, that is the question.");
|
let js = JsString::from("To be, or not to be, that is the question.");
|
||||||
|
@ -93,4 +93,5 @@ fn map_inheritance() {
|
|||||||
let map = Map::new();
|
let map = Map::new();
|
||||||
assert!(map.is_instance_of::<Map>());
|
assert!(map.is_instance_of::<Map>());
|
||||||
assert!(map.is_instance_of::<Object>());
|
assert!(map.is_instance_of::<Object>());
|
||||||
|
let _: &Object = map.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -111,4 +111,5 @@ fn number_inheritance() {
|
|||||||
let n = Number::new(&JsValue::from(42));
|
let n = Number::new(&JsValue::from(42));
|
||||||
assert!(n.is_instance_of::<Number>());
|
assert!(n.is_instance_of::<Number>());
|
||||||
assert!(n.is_instance_of::<Object>());
|
assert!(n.is_instance_of::<Object>());
|
||||||
|
let _: &Object = n.as_ref();
|
||||||
}
|
}
|
||||||
|
11
crates/js-sys/tests/wasm/Promise.rs
Normal file
11
crates/js-sys/tests/wasm/Promise.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use wasm_bindgen_test::*;
|
||||||
|
use wasm_bindgen::JsCast;
|
||||||
|
use js_sys::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn promise_inheritance() {
|
||||||
|
let promise = Promise::new(&mut |_, _| ());
|
||||||
|
assert!(promise.is_instance_of::<Promise>());
|
||||||
|
assert!(promise.is_instance_of::<Object>());
|
||||||
|
let _: &Object = promise.as_ref();
|
||||||
|
}
|
@ -9,6 +9,8 @@ fn range_error() {
|
|||||||
assert!(error.is_instance_of::<RangeError>());
|
assert!(error.is_instance_of::<RangeError>());
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
|
|
||||||
let base: &Error = error.as_ref();
|
let base: &Error = error.as_ref();
|
||||||
assert_eq!(JsValue::from(base.message()), "out of range yo");
|
assert_eq!(JsValue::from(base.message()), "out of range yo");
|
||||||
|
@ -9,6 +9,8 @@ fn reference_error() {
|
|||||||
assert!(error.is_instance_of::<ReferenceError>());
|
assert!(error.is_instance_of::<ReferenceError>());
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
|
|
||||||
let base: &Error = error.as_ref();
|
let base: &Error = error.as_ref();
|
||||||
assert_eq!(JsValue::from(base.message()), "bad reference, fool");
|
assert_eq!(JsValue::from(base.message()), "bad reference, fool");
|
||||||
|
@ -7,6 +7,7 @@ fn regexp_inheritance() {
|
|||||||
let re = RegExp::new(".", "");
|
let re = RegExp::new(".", "");
|
||||||
assert!(re.is_instance_of::<RegExp>());
|
assert!(re.is_instance_of::<RegExp>());
|
||||||
assert!(re.is_instance_of::<Object>());
|
assert!(re.is_instance_of::<Object>());
|
||||||
|
let _: &Object = re.as_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
|
@ -87,4 +87,5 @@ fn set_inheritance() {
|
|||||||
let set = Set::new(&JsValue::undefined());
|
let set = Set::new(&JsValue::undefined());
|
||||||
assert!(set.is_instance_of::<Set>());
|
assert!(set.is_instance_of::<Set>());
|
||||||
assert!(set.is_instance_of::<Object>());
|
assert!(set.is_instance_of::<Object>());
|
||||||
|
let _: &Object = set.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ fn syntax_error() {
|
|||||||
assert!(error.is_instance_of::<SyntaxError>());
|
assert!(error.is_instance_of::<SyntaxError>());
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
|
|
||||||
let base: &Error = error.as_ref();
|
let base: &Error = error.as_ref();
|
||||||
assert_eq!(JsValue::from(base.message()), "msg");
|
assert_eq!(JsValue::from(base.message()), "msg");
|
||||||
|
@ -9,6 +9,8 @@ fn type_error() {
|
|||||||
assert!(error.is_instance_of::<TypeError>());
|
assert!(error.is_instance_of::<TypeError>());
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
|
|
||||||
let base: &Error = error.as_ref();
|
let base: &Error = error.as_ref();
|
||||||
assert_eq!(JsValue::from(base.message()), "msg");
|
assert_eq!(JsValue::from(base.message()), "msg");
|
||||||
|
@ -9,6 +9,8 @@ fn uri_error() {
|
|||||||
assert!(error.is_instance_of::<UriError>());
|
assert!(error.is_instance_of::<UriError>());
|
||||||
assert!(error.is_instance_of::<Error>());
|
assert!(error.is_instance_of::<Error>());
|
||||||
assert!(error.is_instance_of::<Object>());
|
assert!(error.is_instance_of::<Object>());
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
let _: &Object = error.as_ref();
|
||||||
|
|
||||||
let base: &Error = error.as_ref();
|
let base: &Error = error.as_ref();
|
||||||
assert_eq!(JsValue::from(base.message()), "msg");
|
assert_eq!(JsValue::from(base.message()), "msg");
|
||||||
|
@ -57,4 +57,5 @@ fn weakmap_inheritance() {
|
|||||||
let map = WeakMap::new();
|
let map = WeakMap::new();
|
||||||
assert!(map.is_instance_of::<WeakMap>());
|
assert!(map.is_instance_of::<WeakMap>());
|
||||||
assert!(map.is_instance_of::<Object>());
|
assert!(map.is_instance_of::<Object>());
|
||||||
|
let _: &Object = map.as_ref();
|
||||||
}
|
}
|
||||||
|
@ -47,4 +47,5 @@ fn weakset_inheritance() {
|
|||||||
let set = WeakSet::new();
|
let set = WeakSet::new();
|
||||||
assert!(set.is_instance_of::<WeakSet>());
|
assert!(set.is_instance_of::<WeakSet>());
|
||||||
assert!(set.is_instance_of::<Object>());
|
assert!(set.is_instance_of::<Object>());
|
||||||
|
let _: &Object = set.as_ref();
|
||||||
}
|
}
|
||||||
|
28
crates/js-sys/tests/wasm/WebAssembly.js
Normal file
28
crates/js-sys/tests/wasm/WebAssembly.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
const { TextEncoder } = require("util");
|
||||||
|
|
||||||
|
const data =
|
||||||
|
"\u0000asm\u0001\u0000\u0000\u0000\u0001\b\u0002`\u0001\u007f\u0000`\u0000" +
|
||||||
|
"\u0000\u0002\u0019\u0001\u0007imports\rimported_func\u0000\u0000\u0003" +
|
||||||
|
"\u0002\u0001\u0001\u0007\u0011\u0001\rexported_func\u0000\u0001\n\b\u0001" +
|
||||||
|
"\u0006\u0000A*\u0010\u0000\u000b";
|
||||||
|
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const wasmArray = encoder.encode(data);
|
||||||
|
|
||||||
|
function getWasmArray() {
|
||||||
|
return wasmArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTableObject() {
|
||||||
|
return { element: "anyfunc", initial: 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInvalidTableObject() {
|
||||||
|
return { element: "anyfunc", initial: 1, maximum: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getInvalidTableObject,
|
||||||
|
getTableObject,
|
||||||
|
getWasmArray,
|
||||||
|
};
|
@ -1,9 +1,172 @@
|
|||||||
use wasm_bindgen_test::*;
|
use futures::Future;
|
||||||
use js_sys::*;
|
use js_sys::*;
|
||||||
|
use wasm_bindgen::{JsCast, prelude::*};
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen(module = "tests/wasm/WebAssembly.js")]
|
||||||
|
extern {
|
||||||
|
#[wasm_bindgen(js_name = getWasmArray)]
|
||||||
|
fn get_wasm_array() -> Uint8Array;
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = getTableObject)]
|
||||||
|
fn get_table_object() -> Object;
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = getInvalidTableObject)]
|
||||||
|
fn get_invalid_table_object() -> Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_invalid_wasm() -> JsValue {
|
||||||
|
ArrayBuffer::new(42).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_bad_type_wasm() -> JsValue {
|
||||||
|
2.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_valid_wasm() -> JsValue {
|
||||||
|
get_wasm_array().into()
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn validate() {
|
fn validate() {
|
||||||
assert!(!WebAssembly::validate(&ArrayBuffer::new(42).into()).unwrap());
|
assert!(!WebAssembly::validate(&get_invalid_wasm()).unwrap());
|
||||||
|
|
||||||
assert!(WebAssembly::validate(&2.into()).is_err());
|
assert!(WebAssembly::validate(&get_bad_type_wasm()).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test(async)]
|
||||||
|
fn compile_compile_error() -> impl Future<Item = (), Error = JsValue> {
|
||||||
|
let p = WebAssembly::compile(&get_invalid_wasm());
|
||||||
|
JsFuture::from(p)
|
||||||
|
.map(|_| unreachable!())
|
||||||
|
.or_else(|e| {
|
||||||
|
assert!(e.is_instance_of::<WebAssembly::CompileError>());
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test(async)]
|
||||||
|
fn compile_type_error() -> impl Future<Item = (), Error = JsValue> {
|
||||||
|
let p = WebAssembly::compile(&get_bad_type_wasm());
|
||||||
|
JsFuture::from(p)
|
||||||
|
.map(|_| unreachable!())
|
||||||
|
.or_else(|e| {
|
||||||
|
assert!(e.is_instance_of::<TypeError>());
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test(async)]
|
||||||
|
fn compile_valid() -> impl Future<Item = (), Error = JsValue> {
|
||||||
|
let p = WebAssembly::compile(&get_valid_wasm());
|
||||||
|
JsFuture::from(p)
|
||||||
|
.map(|module| {
|
||||||
|
assert!(module.is_instance_of::<WebAssembly::Module>());
|
||||||
|
})
|
||||||
|
.map_err(|_| unreachable!())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_inheritance() {
|
||||||
|
let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap();
|
||||||
|
assert!(module.is_instance_of::<WebAssembly::Module>());
|
||||||
|
assert!(module.is_instance_of::<Object>());
|
||||||
|
|
||||||
|
let _: &Object = module.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_error() {
|
||||||
|
let error = WebAssembly::Module::new(&get_invalid_wasm()).err().unwrap();
|
||||||
|
assert!(error.is_instance_of::<WebAssembly::CompileError>());
|
||||||
|
|
||||||
|
let error = WebAssembly::Module::new(&get_bad_type_wasm()).err().unwrap();
|
||||||
|
assert!(error.is_instance_of::<TypeError>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_custom_sections() {
|
||||||
|
let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap();
|
||||||
|
let cust_sec = WebAssembly::Module::custom_sections(&module, "abcd");
|
||||||
|
assert_eq!(cust_sec.length(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_exports() {
|
||||||
|
let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap();
|
||||||
|
let exports = WebAssembly::Module::exports(&module);
|
||||||
|
assert_eq!(exports.length(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn module_imports() {
|
||||||
|
let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap();
|
||||||
|
let imports = WebAssembly::Module::imports(&module);
|
||||||
|
assert_eq!(imports.length(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn table_inheritance() {
|
||||||
|
let table = WebAssembly::Table::new(&get_table_object().into()).unwrap();
|
||||||
|
assert!(table.is_instance_of::<WebAssembly::Table>());
|
||||||
|
assert!(table.is_instance_of::<Object>());
|
||||||
|
|
||||||
|
let _: &Object = table.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn table_error() {
|
||||||
|
let error = WebAssembly::Table::new(&get_invalid_table_object()).err().unwrap();
|
||||||
|
assert!(error.is_instance_of::<RangeError>());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn table() {
|
||||||
|
let table = WebAssembly::Table::new(&get_table_object().into()).unwrap();
|
||||||
|
assert_eq!(table.length(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn compile_error_inheritance() {
|
||||||
|
let error = WebAssembly::CompileError::new("");
|
||||||
|
assert!(error.is_instance_of::<WebAssembly::CompileError>());
|
||||||
|
assert!(error.is_instance_of::<Error>());
|
||||||
|
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn link_error_inheritance() {
|
||||||
|
let error = WebAssembly::LinkError::new("");
|
||||||
|
assert!(error.is_instance_of::<WebAssembly::LinkError>());
|
||||||
|
assert!(error.is_instance_of::<Error>());
|
||||||
|
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn runtime_error_inheritance() {
|
||||||
|
let error = WebAssembly::RuntimeError::new("");
|
||||||
|
assert!(error.is_instance_of::<WebAssembly::RuntimeError>());
|
||||||
|
assert!(error.is_instance_of::<Error>());
|
||||||
|
|
||||||
|
let _: &Error = error.as_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn memory_works() {
|
||||||
|
let obj = Object::new();
|
||||||
|
Reflect::set(obj.as_ref(), &"initial".into(), &1.into());
|
||||||
|
let mem = WebAssembly::Memory::new(&obj).unwrap();
|
||||||
|
assert!(mem.is_instance_of::<WebAssembly::Memory>());
|
||||||
|
assert!(mem.is_instance_of::<Object>());
|
||||||
|
assert!(mem.buffer().is_instance_of::<ArrayBuffer>());
|
||||||
|
assert_eq!(mem.grow(1), 1);
|
||||||
|
assert_eq!(mem.grow(2), 2);
|
||||||
|
assert_eq!(mem.grow(3), 4);
|
||||||
|
assert_eq!(
|
||||||
|
mem.buffer().dyn_into::<ArrayBuffer>().unwrap().byte_length(),
|
||||||
|
7 * 64 * 1024,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
#![cfg(target_arch = "wasm32")]
|
#![cfg(target_arch = "wasm32")]
|
||||||
#![feature(use_extern_macros)]
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
extern crate futures;
|
||||||
extern crate js_sys;
|
extern crate js_sys;
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
extern crate wasm_bindgen_futures;
|
||||||
extern crate wasm_bindgen_test;
|
extern crate wasm_bindgen_test;
|
||||||
|
|
||||||
pub mod global_fns;
|
pub mod global_fns;
|
||||||
@ -25,6 +26,7 @@ pub mod MapIterator;
|
|||||||
pub mod Math;
|
pub mod Math;
|
||||||
pub mod Number;
|
pub mod Number;
|
||||||
pub mod Object;
|
pub mod Object;
|
||||||
|
pub mod Promise;
|
||||||
pub mod Proxy;
|
pub mod Proxy;
|
||||||
pub mod RangeError;
|
pub mod RangeError;
|
||||||
pub mod ReferenceError;
|
pub mod ReferenceError;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support"
|
||||||
@ -11,12 +11,12 @@ The part of the implementation of the `#[wasm_bindgen]` attribute that is not in
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
spans = ["proc-macro2/nightly", "wasm-bindgen-backend/spans"]
|
spans = ["wasm-bindgen-backend/spans"]
|
||||||
extra-traits = ["syn/extra-traits"]
|
extra-traits = ["syn/extra-traits"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
syn = { version = '0.14', features = ['full'] }
|
syn = { version = '0.14', features = ['full'] }
|
||||||
quote = '0.6'
|
quote = '0.6'
|
||||||
proc-macro2 = "0.4.9"
|
proc-macro2 = "0.4.9"
|
||||||
wasm-bindgen-backend = { path = "../backend", version = "=0.2.17" }
|
wasm-bindgen-backend = { path = "../backend", version = "=0.2.19" }
|
||||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.17" }
|
wasm-bindgen-shared = { path = "../shared", version = "=0.2.19" }
|
||||||
|
@ -500,7 +500,7 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
|
|
||||||
ast::ImportFunctionKind::Method { class, ty, kind }
|
ast::ImportFunctionKind::Method { class, ty, kind }
|
||||||
} else if opts.constructor() {
|
} else if opts.constructor() {
|
||||||
let class = match wasm.ret {
|
let class = match js_ret {
|
||||||
Some(ref ty) => ty,
|
Some(ref ty) => ty,
|
||||||
_ => bail_span!(self, "constructor returns must be bare types"),
|
_ => bail_span!(self, "constructor returns must be bare types"),
|
||||||
};
|
};
|
||||||
@ -528,6 +528,7 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
|
|||||||
|
|
||||||
let shim = {
|
let shim = {
|
||||||
let ns = match kind {
|
let ns = match kind {
|
||||||
|
ast::ImportFunctionKind::ScopedMethod { .. } |
|
||||||
ast::ImportFunctionKind::Normal => (0, "n"),
|
ast::ImportFunctionKind::Normal => (0, "n"),
|
||||||
ast::ImportFunctionKind::Method { ref class, .. } => (1, &class[..]),
|
ast::ImportFunctionKind::Method { ref class, .. } => (1, &class[..]),
|
||||||
};
|
};
|
||||||
@ -576,10 +577,12 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
|
impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemStatic {
|
||||||
type Target = ast::ImportKind;
|
type Target = ast::ImportKind;
|
||||||
|
|
||||||
fn convert(self, opts: BindgenAttrs) -> Result<Self::Target, Diagnostic> {
|
fn convert(self, (opts, module): (BindgenAttrs, &'a Option<String>))
|
||||||
|
-> Result<Self::Target, Diagnostic>
|
||||||
|
{
|
||||||
if self.mutability.is_some() {
|
if self.mutability.is_some() {
|
||||||
bail_span!(self.mutability, "cannot import mutable globals yet")
|
bail_span!(self.mutability, "cannot import mutable globals yet")
|
||||||
}
|
}
|
||||||
@ -588,11 +591,8 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
|
|||||||
let js_name = opts.js_name().unwrap_or(&default_name);
|
let js_name = opts.js_name().unwrap_or(&default_name);
|
||||||
let shim = format!(
|
let shim = format!(
|
||||||
"__wbg_static_accessor_{}_{}",
|
"__wbg_static_accessor_{}_{}",
|
||||||
js_name
|
self.ident,
|
||||||
.chars()
|
ShortHash((&js_name, module, &self.ident)),
|
||||||
.filter(|c| c.is_ascii_alphanumeric())
|
|
||||||
.collect::<String>(),
|
|
||||||
self.ident
|
|
||||||
);
|
);
|
||||||
Ok(ast::ImportKind::Static(ast::ImportStatic {
|
Ok(ast::ImportKind::Static(ast::ImportStatic {
|
||||||
ty: *self.ty,
|
ty: *self.ty,
|
||||||
@ -991,7 +991,7 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
|
|||||||
let kind = match self {
|
let kind = match self {
|
||||||
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?,
|
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?,
|
||||||
syn::ForeignItem::Type(t) => t.convert(item_opts)?,
|
syn::ForeignItem::Type(t) => t.convert(item_opts)?,
|
||||||
syn::ForeignItem::Static(s) => s.convert(item_opts)?,
|
syn::ForeignItem::Static(s) => s.convert((item_opts, &module))?,
|
||||||
_ => panic!("only foreign functions/types allowed for now"),
|
_ => panic!("only foreign functions/types allowed for now"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro"
|
||||||
@ -18,5 +18,5 @@ spans = ["wasm-bindgen-macro-support/spans"]
|
|||||||
xxx_debug_only_print_generated_code = []
|
xxx_debug_only_print_generated_code = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.17" }
|
wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.19" }
|
||||||
quote = "0.6"
|
quote = "0.6"
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
||||||
--> $DIR/attribute-fails-to-parse.rs:7:16
|
--> $DIR/attribute-fails-to-parse.rs:5:16
|
||||||
|
|
|
|
||||||
7 | #[wasm_bindgen(nonsense)]
|
5 | #[wasm_bindgen(nonsense)]
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
error: cannot return a borrowed ref with #[wasm_bindgen]
|
error: cannot return a borrowed ref with #[wasm_bindgen]
|
||||||
--> $DIR/bad-signatures.rs:8:17
|
--> $DIR/bad-signatures.rs:6:17
|
||||||
|
|
|
|
||||||
8 | pub fn foo() -> &u32 {}
|
6 | pub fn foo() -> &u32 {}
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: unsupported pattern in #[wasm_bindgen] imported function
|
error: unsupported pattern in #[wasm_bindgen] imported function
|
||||||
--> $DIR/bad-signatures.rs:12:12
|
--> $DIR/bad-signatures.rs:10:12
|
||||||
|
|
|
|
||||||
12 | fn foo(Foo(x): Foo);
|
10 | fn foo(Foo(x): Foo);
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: cannot return references in #[wasm_bindgen] imports yet
|
error: cannot return references in #[wasm_bindgen] imports yet
|
||||||
--> $DIR/bad-signatures.rs:14:17
|
--> $DIR/bad-signatures.rs:12:17
|
||||||
|
|
|
|
||||||
14 | fn foo() -> &u32;
|
12 | fn foo() -> &u32;
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
||||||
--> $DIR/invalid-attr.rs:7:16
|
--> $DIR/invalid-attr.rs:5:16
|
||||||
|
|
|
|
||||||
7 | #[wasm_bindgen(x)]
|
5 | #[wasm_bindgen(x)]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
error: error parsing #[wasm_bindgen] attribute options: failed to parse anything
|
||||||
--> $DIR/invalid-attr.rs:12:20
|
--> $DIR/invalid-attr.rs:10:20
|
||||||
|
|
|
|
||||||
12 | #[wasm_bindgen(y)]
|
10 | #[wasm_bindgen(y)]
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: malformed #[wasm_bindgen] attribute
|
error: malformed #[wasm_bindgen] attribute
|
||||||
--> $DIR/invalid-attr.rs:15:5
|
--> $DIR/invalid-attr.rs:13:5
|
||||||
|
|
|
|
||||||
15 | #[wasm_bindgen { }]
|
13 | #[wasm_bindgen { }]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
error: only public enums are allowed with #[wasm_bindgen]
|
error: only public enums are allowed with #[wasm_bindgen]
|
||||||
--> $DIR/invalid-enums.rs:8:1
|
--> $DIR/invalid-enums.rs:6:1
|
||||||
|
|
|
|
||||||
8 | enum A {}
|
6 | enum A {}
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: only C-Style enums allowed with #[wasm_bindgen]
|
error: only C-Style enums allowed with #[wasm_bindgen]
|
||||||
--> $DIR/invalid-enums.rs:12:6
|
--> $DIR/invalid-enums.rs:10:6
|
||||||
|
|
|
|
||||||
12 | D(u32),
|
10 | D(u32),
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: enums with #[wasm_bidngen] may only have number literal values
|
error: enums with #[wasm_bidngen] may only have number literal values
|
||||||
--> $DIR/invalid-enums.rs:17:9
|
--> $DIR/invalid-enums.rs:15:9
|
||||||
|
|
|
|
||||||
17 | X = 1 + 3,
|
15 | X = 1 + 3,
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: enums with #[wasm_bindgen] can only support numbers that can be represented as u32
|
error: enums with #[wasm_bindgen] can only support numbers that can be represented as u32
|
||||||
--> $DIR/invalid-enums.rs:22:9
|
--> $DIR/invalid-enums.rs:20:9
|
||||||
|
|
|
|
||||||
22 | X = 4294967296,
|
20 | X = 4294967296,
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,91 +1,91 @@
|
|||||||
error: it is currently not sound to use lifetimes in function signatures
|
error: it is currently not sound to use lifetimes in function signatures
|
||||||
--> $DIR/invalid-imports.rs:11:16
|
--> $DIR/invalid-imports.rs:9:16
|
||||||
|
|
|
|
||||||
11 | fn f() -> &'static u32;
|
9 | fn f() -> &'static u32;
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: imported methods must have at least one argument
|
error: imported methods must have at least one argument
|
||||||
--> $DIR/invalid-imports.rs:14:5
|
--> $DIR/invalid-imports.rs:12:5
|
||||||
|
|
|
|
||||||
14 | fn f1();
|
12 | fn f1();
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: first argument of method must be a shared reference
|
error: first argument of method must be a shared reference
|
||||||
--> $DIR/invalid-imports.rs:16:14
|
--> $DIR/invalid-imports.rs:14:14
|
||||||
|
|
|
|
||||||
16 | fn f2(x: u32);
|
14 | fn f2(x: u32);
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: first argument of method must be a path
|
error: first argument of method must be a path
|
||||||
--> $DIR/invalid-imports.rs:18:14
|
--> $DIR/invalid-imports.rs:16:14
|
||||||
|
|
|
|
||||||
18 | fn f3(x: &&u32);
|
16 | fn f3(x: &&u32);
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: multi-segment paths are not supported yet
|
error: multi-segment paths are not supported yet
|
||||||
--> $DIR/invalid-imports.rs:20:15
|
--> $DIR/invalid-imports.rs:18:15
|
||||||
|
|
|
|
||||||
20 | fn f4(x: &foo::Bar);
|
18 | fn f4(x: &foo::Bar);
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: global paths are not supported yet
|
error: global paths are not supported yet
|
||||||
|
--> $DIR/invalid-imports.rs:20:15
|
||||||
|
|
|
||||||
|
20 | fn f4(x: &::Bar);
|
||||||
|
| ^^^^^
|
||||||
|
|
||||||
|
error: paths with type parameters are not supported yet
|
||||||
--> $DIR/invalid-imports.rs:22:15
|
--> $DIR/invalid-imports.rs:22:15
|
||||||
|
|
|
|
||||||
22 | fn f4(x: &::Bar);
|
22 | fn f4(x: &Bar<T>);
|
||||||
| ^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: paths with type parameters are not supported yet
|
error: paths with type parameters are not supported yet
|
||||||
--> $DIR/invalid-imports.rs:24:15
|
--> $DIR/invalid-imports.rs:24:15
|
||||||
|
|
|
|
||||||
24 | fn f4(x: &Bar<T>);
|
24 | fn f4(x: &Fn(T));
|
||||||
| ^^^^^^
|
|
||||||
|
|
||||||
error: paths with type parameters are not supported yet
|
|
||||||
--> $DIR/invalid-imports.rs:26:15
|
|
||||||
|
|
|
||||||
26 | fn f4(x: &Fn(T));
|
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: constructor returns must be bare types
|
error: constructor returns must be bare types
|
||||||
--> $DIR/invalid-imports.rs:29:5
|
--> $DIR/invalid-imports.rs:27:5
|
||||||
|
|
|
|
||||||
29 | fn f();
|
27 | fn f();
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: global paths are not supported yet
|
error: global paths are not supported yet
|
||||||
--> $DIR/invalid-imports.rs:31:15
|
--> $DIR/invalid-imports.rs:29:15
|
||||||
|
|
|
|
||||||
31 | fn f() -> ::Bar;
|
29 | fn f() -> ::Bar;
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: return value of constructor must be a bare path
|
error: return value of constructor must be a bare path
|
||||||
--> $DIR/invalid-imports.rs:33:5
|
--> $DIR/invalid-imports.rs:31:5
|
||||||
|
|
|
|
||||||
33 | fn f() -> &Bar;
|
31 | fn f() -> &Bar;
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: must be Result<...>
|
||||||
|
--> $DIR/invalid-imports.rs:34:15
|
||||||
|
|
|
||||||
|
34 | fn f() -> u32;
|
||||||
|
| ^^^
|
||||||
|
|
||||||
error: must be Result<...>
|
error: must be Result<...>
|
||||||
--> $DIR/invalid-imports.rs:36:15
|
--> $DIR/invalid-imports.rs:36:15
|
||||||
|
|
|
|
||||||
36 | fn f() -> u32;
|
36 | fn f() -> &u32;
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: must be Result<...>
|
|
||||||
--> $DIR/invalid-imports.rs:38:15
|
|
||||||
|
|
|
||||||
38 | fn f() -> &u32;
|
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: must have at least one generic parameter
|
error: must have at least one generic parameter
|
||||||
--> $DIR/invalid-imports.rs:40:15
|
--> $DIR/invalid-imports.rs:38:15
|
||||||
|
|
|
|
||||||
40 | fn f() -> Result<>;
|
38 | fn f() -> Result<>;
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: it is currently not sound to use lifetimes in function signatures
|
error: it is currently not sound to use lifetimes in function signatures
|
||||||
--> $DIR/invalid-imports.rs:42:22
|
--> $DIR/invalid-imports.rs:40:22
|
||||||
|
|
|
|
||||||
42 | fn f() -> Result<'a>;
|
40 | fn f() -> Result<'a>;
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: aborting due to 15 previous errors
|
error: aborting due to 15 previous errors
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,67 +1,67 @@
|
|||||||
error: can only #[wasm_bindgen] public functions
|
error: can only #[wasm_bindgen] public functions
|
||||||
--> $DIR/invalid-items.rs:8:1
|
--> $DIR/invalid-items.rs:6:1
|
||||||
|
|
|
|
||||||
8 | fn foo() {}
|
6 | fn foo() {}
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: can only #[wasm_bindgen] safe functions
|
error: can only #[wasm_bindgen] safe functions
|
||||||
--> $DIR/invalid-items.rs:11:5
|
--> $DIR/invalid-items.rs:9:5
|
||||||
|
|
|
|
||||||
11 | pub unsafe fn foo1() {}
|
9 | pub unsafe fn foo1() {}
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: can only #[wasm_bindgen] non-const functions
|
error: can only #[wasm_bindgen] non-const functions
|
||||||
--> $DIR/invalid-items.rs:14:5
|
--> $DIR/invalid-items.rs:12:5
|
||||||
|
|
|
|
||||||
14 | pub const fn foo2() {}
|
12 | pub const fn foo2() {}
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently
|
error: structs with #[wasm_bindgen] cannot have lifetime or type parameters currently
|
||||||
--> $DIR/invalid-items.rs:17:11
|
--> $DIR/invalid-items.rs:15:11
|
||||||
|
|
|
|
||||||
17 | struct Foo<T>(T);
|
15 | struct Foo<T>(T);
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: cannot import mutable globals yet
|
error: cannot import mutable globals yet
|
||||||
--> $DIR/invalid-items.rs:21:12
|
--> $DIR/invalid-items.rs:19:12
|
||||||
|
|
|
|
||||||
21 | static mut FOO: u32;
|
19 | static mut FOO: u32;
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: can't #[wasm_bindgen] variadic functions
|
error: can't #[wasm_bindgen] variadic functions
|
||||||
--> $DIR/invalid-items.rs:23:25
|
--> $DIR/invalid-items.rs:21:25
|
||||||
|
|
|
|
||||||
23 | pub fn foo3(x: i32, ...);
|
21 | pub fn foo3(x: i32, ...);
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: only foreign mods with the `C` ABI are allowed
|
error: only foreign mods with the `C` ABI are allowed
|
||||||
--> $DIR/invalid-items.rs:27:8
|
--> $DIR/invalid-items.rs:25:8
|
||||||
|
|
|
|
||||||
27 | extern "system" {
|
25 | extern "system" {
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||||
|
--> $DIR/invalid-items.rs:29:12
|
||||||
|
|
|
||||||
|
29 | pub fn foo4<T>() {}
|
||||||
|
| ^^^
|
||||||
|
|
||||||
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||||
--> $DIR/invalid-items.rs:31:12
|
--> $DIR/invalid-items.rs:31:12
|
||||||
|
|
|
|
||||||
31 | pub fn foo4<T>() {}
|
31 | pub fn foo5<'a>() {}
|
||||||
| ^^^
|
| ^^^^
|
||||||
|
|
||||||
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||||
--> $DIR/invalid-items.rs:33:12
|
--> $DIR/invalid-items.rs:33:12
|
||||||
|
|
|
|
||||||
33 | pub fn foo5<'a>() {}
|
33 | pub fn foo6<'a, T>() {}
|
||||||
| ^^^^
|
|
||||||
|
|
||||||
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
|
||||||
--> $DIR/invalid-items.rs:35:12
|
|
||||||
|
|
|
||||||
35 | pub fn foo6<'a, T>() {}
|
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: #[wasm_bindgen] can only be applied to a function, struct, enum, impl, or extern block
|
error: #[wasm_bindgen] can only be applied to a function, struct, enum, impl, or extern block
|
||||||
--> $DIR/invalid-items.rs:38:1
|
--> $DIR/invalid-items.rs:36:1
|
||||||
|
|
|
|
||||||
38 | trait X {}
|
36 | trait X {}
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
error: aborting due to 11 previous errors
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,61 +1,61 @@
|
|||||||
error: #[wasm_bindgen] default impls are not supported
|
error: #[wasm_bindgen] default impls are not supported
|
||||||
--> $DIR/invalid-methods.rs:11:1
|
--> $DIR/invalid-methods.rs:9:1
|
||||||
|
|
|
|
||||||
11 | default impl A {
|
9 | default impl A {
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: #[wasm_bindgen] unsafe impls are not supported
|
error: #[wasm_bindgen] unsafe impls are not supported
|
||||||
--> $DIR/invalid-methods.rs:15:1
|
--> $DIR/invalid-methods.rs:13:1
|
||||||
|
|
|
|
||||||
15 | unsafe impl A {
|
13 | unsafe impl A {
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: #[wasm_bindgen] trait impls are not supported
|
error: #[wasm_bindgen] trait impls are not supported
|
||||||
--> $DIR/invalid-methods.rs:19:6
|
--> $DIR/invalid-methods.rs:17:6
|
||||||
|
|
|
|
||||||
19 | impl Clone for A {
|
17 | impl Clone for A {
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: #[wasm_bindgen] generic impls aren't supported
|
error: #[wasm_bindgen] generic impls aren't supported
|
||||||
--> $DIR/invalid-methods.rs:23:5
|
--> $DIR/invalid-methods.rs:21:5
|
||||||
|
|
|
|
||||||
23 | impl<T> A {
|
21 | impl<T> A {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: unsupported self type in #[wasm_bindgen] impl
|
error: unsupported self type in #[wasm_bindgen] impl
|
||||||
--> $DIR/invalid-methods.rs:27:6
|
--> $DIR/invalid-methods.rs:25:6
|
||||||
|
|
|
|
||||||
27 | impl &'static A {
|
25 | impl &'static A {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: const definitions aren't supported with #[wasm_bindgen]
|
error: const definitions aren't supported with #[wasm_bindgen]
|
||||||
--> $DIR/invalid-methods.rs:34:5
|
--> $DIR/invalid-methods.rs:32:5
|
||||||
|
|
|
|
||||||
34 | const X: u32 = 3;
|
32 | const X: u32 = 3;
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: type definitions in impls aren't supported with #[wasm_bindgen]
|
error: type definitions in impls aren't supported with #[wasm_bindgen]
|
||||||
--> $DIR/invalid-methods.rs:35:5
|
--> $DIR/invalid-methods.rs:33:5
|
||||||
|
|
|
|
||||||
35 | type Y = u32;
|
33 | type Y = u32;
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: macros in impls aren't supported
|
error: macros in impls aren't supported
|
||||||
--> $DIR/invalid-methods.rs:36:5
|
--> $DIR/invalid-methods.rs:34:5
|
||||||
|
|
|
|
||||||
36 | x!();
|
34 | x!();
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: can only #[wasm_bindgen] non-const functions
|
error: can only #[wasm_bindgen] non-const functions
|
||||||
--> $DIR/invalid-methods.rs:41:9
|
--> $DIR/invalid-methods.rs:39:9
|
||||||
|
|
|
|
||||||
41 | pub const fn foo() {}
|
39 | pub const fn foo() {}
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: can only bindgen safe functions
|
error: can only bindgen safe functions
|
||||||
--> $DIR/invalid-methods.rs:42:9
|
--> $DIR/invalid-methods.rs:40:9
|
||||||
|
|
|
|
||||||
42 | pub unsafe fn foo() {}
|
40 | pub unsafe fn foo() {}
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 10 previous errors
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
error: can only #[wasm_bindgen] public functions
|
error: can only #[wasm_bindgen] public functions
|
||||||
--> $DIR/non-public-function.rs:8:1
|
--> $DIR/non-public-function.rs:6:1
|
||||||
|
|
|
|
||||||
8 | fn foo() {}
|
6 | fn foo() {}
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared"
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared"
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
|
|
||||||
pub const SCHEMA_VERSION: &str = "8";
|
// The schema is so unstable right now we just force it to change whenever this
|
||||||
|
// package's version changes, which happens on all publishes.
|
||||||
|
pub const SCHEMA_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ProgramOnlySchema {
|
pub struct ProgramOnlySchema {
|
||||||
@ -49,7 +51,7 @@ pub struct ImportFunction {
|
|||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct MethodData {
|
pub struct MethodData {
|
||||||
pub class: String,
|
pub class: Option<String>,
|
||||||
pub kind: MethodKind,
|
pub kind: MethodKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-test-macro"
|
name = "wasm-bindgen-test-macro"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
description = "Internal testing macro for wasm-bindgen"
|
description = "Internal testing macro for wasm-bindgen"
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
repository = "https://github.com/rustwasm/wasm-bindgen"
|
repository = "https://github.com/rustwasm/wasm-bindgen"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
proc-macro2 = { version = "0.4", features = ['nightly'] }
|
proc-macro2 = "0.4"
|
||||||
quote = "0.6"
|
quote = "0.6"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm-bindgen-test"
|
name = "wasm-bindgen-test"
|
||||||
version = "0.2.17"
|
version = "0.2.19"
|
||||||
authors = ["The wasm-bindgen Developers"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
description = "Internal testing crate for wasm-bindgen"
|
description = "Internal testing crate for wasm-bindgen"
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
@ -9,11 +9,11 @@ repository = "https://github.com/rustwasm/wasm-bindgen"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
console_error_panic_hook = '0.1'
|
console_error_panic_hook = '0.1'
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
js-sys = { path = '../js-sys', version = '0.2.1' }
|
js-sys = { path = '../js-sys', version = '0.2.4' }
|
||||||
scoped-tls = "0.1"
|
scoped-tls = "0.1"
|
||||||
wasm-bindgen = { path = '../..', version = '0.2.17' }
|
wasm-bindgen = { path = '../..', version = '0.2.19' }
|
||||||
wasm-bindgen-futures = { path = '../futures', version = '0.2.17' }
|
wasm-bindgen-futures = { path = '../futures', version = '0.2.19' }
|
||||||
wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.17' }
|
wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.19' }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
test = false
|
test = false
|
||||||
|
@ -38,8 +38,6 @@ ton of documentation just yet, but a taste of how it works is:
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
// in tests/wasm.rs
|
// in tests/wasm.rs
|
||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate wasm_bindgen_test;
|
extern crate wasm_bindgen_test;
|
||||||
|
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate js_sys;
|
extern crate js_sys;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate sample;
|
extern crate sample;
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
extern crate sample;
|
extern crate sample;
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
//!
|
//!
|
||||||
//! More documentation can be found in the README for this crate!
|
//! More documentation can be found in the README for this crate!
|
||||||
|
|
||||||
#![feature(use_extern_macros)]
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
extern crate console_error_panic_hook;
|
extern crate console_error_panic_hook;
|
||||||
|
17
crates/wasm-interpreter/Cargo.toml
Normal file
17
crates/wasm-interpreter/Cargo.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "wasm-bindgen-wasm-interpreter"
|
||||||
|
version = "0.2.19"
|
||||||
|
authors = ["The wasm-bindgen Developers"]
|
||||||
|
license = "MIT/Apache-2.0"
|
||||||
|
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/wasm-interpreter"
|
||||||
|
homepage = "https://rustwasm.github.io/wasm-bindgen/"
|
||||||
|
documentation = "https://docs.rs/wasm-bindgen-wasm-interpreter"
|
||||||
|
description = """
|
||||||
|
Micro-interpreter optimized for wasm-bindgen's use case
|
||||||
|
"""
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
parity-wasm = "0.32"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3"
|
243
crates/wasm-interpreter/src/lib.rs
Normal file
243
crates/wasm-interpreter/src/lib.rs
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
//! A tiny and incomplete wasm interpreter
|
||||||
|
//!
|
||||||
|
//! This module contains a tiny and incomplete wasm interpreter built on top of
|
||||||
|
//! `parity-wasm`'s module structure. Each `Interpreter` contains some state
|
||||||
|
//! about the execution of a wasm instance. The "incomplete" part here is
|
||||||
|
//! related to the fact that this is *only* used to execute the various
|
||||||
|
//! descriptor functions for wasm-bindgen.
|
||||||
|
//!
|
||||||
|
//! As a recap, the wasm-bindgen macro generate "descriptor functions" which
|
||||||
|
//! basically as a mapping of rustc's trait resolution in executable code. This
|
||||||
|
//! allows us to detect, after the macro is invoke, what trait selection did and
|
||||||
|
//! what types of functions look like. By executing descriptor functions they'll
|
||||||
|
//! each invoke a known import (with only one argument) some number of times,
|
||||||
|
//! which gives us a list of `u32` values to then decode.
|
||||||
|
//!
|
||||||
|
//! The interpreter here is only geared towards this one exact use case, so it's
|
||||||
|
//! quite small and likely not extra-efficient.
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
|
extern crate parity_wasm;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use parity_wasm::elements::*;
|
||||||
|
|
||||||
|
/// A ready-to-go interpreter of a wasm module.
|
||||||
|
///
|
||||||
|
/// An interpreter currently represents effectively cached state. It is reused
|
||||||
|
/// between calls to `interpret` and is precomputed from a `Module`. It houses
|
||||||
|
/// state like the wasm stack, wasm memory, etc.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Interpreter {
|
||||||
|
// Number of imported functions in the wasm module (used in index
|
||||||
|
// calculations)
|
||||||
|
imports: usize,
|
||||||
|
|
||||||
|
// Function index of the `__wbindgen_describe` imported function. We special
|
||||||
|
// case this to know when the environment's imported function is called.
|
||||||
|
describe_idx: Option<u32>,
|
||||||
|
|
||||||
|
// A mapping of string names to the function index, filled with all exported
|
||||||
|
// functions.
|
||||||
|
name_map: HashMap<String, u32>,
|
||||||
|
|
||||||
|
// The numerical index of the code section in the wasm module, indexed into
|
||||||
|
// the module's list of sections.
|
||||||
|
code_idx: Option<usize>,
|
||||||
|
|
||||||
|
// The current stack pointer (global 0) and wasm memory (the stack). Only
|
||||||
|
// used in a limited capacity.
|
||||||
|
sp: i32,
|
||||||
|
mem: Vec<i32>,
|
||||||
|
|
||||||
|
// The wasm stack. Note how it's just `i32` which is intentional, we don't
|
||||||
|
// support other types.
|
||||||
|
stack: Vec<i32>,
|
||||||
|
|
||||||
|
// The descriptor which we're assembling, a list of `u32` entries. This is
|
||||||
|
// very specific to wasm-bindgen and is the purpose for the existence of
|
||||||
|
// this module.
|
||||||
|
descriptor: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Interpreter {
|
||||||
|
/// Creates a new interpreter from a provided `Module`, precomputing all
|
||||||
|
/// information necessary to interpret further.
|
||||||
|
///
|
||||||
|
/// Note that the `module` passed in to this function must be the same as
|
||||||
|
/// the `module` passed to `interpret` below.
|
||||||
|
pub fn new(module: &Module) -> Interpreter {
|
||||||
|
let mut ret = Interpreter::default();
|
||||||
|
|
||||||
|
// The descriptor functions shouldn't really use all that much memory
|
||||||
|
// (the LLVM call stack, now the wasm stack). To handle that let's give
|
||||||
|
// our selves a little bit of memory and set the stack pointer (global
|
||||||
|
// 0) to the top.
|
||||||
|
ret.mem = vec![0; 0x100];
|
||||||
|
ret.sp = ret.mem.len() as i32;
|
||||||
|
|
||||||
|
// Figure out where our code section, if any, is.
|
||||||
|
for (i, s) in module.sections().iter().enumerate() {
|
||||||
|
match s {
|
||||||
|
Section::Code(_) => ret.code_idx = Some(i),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out where the `__wbindgen_describe` imported function is, if
|
||||||
|
// it exists. We'll special case calls to this function as our
|
||||||
|
// interpretation should only invoke this function as an imported
|
||||||
|
// function.
|
||||||
|
if let Some(i) = module.import_section() {
|
||||||
|
ret.imports = i.functions();
|
||||||
|
let mut idx = 0;
|
||||||
|
for entry in i.entries() {
|
||||||
|
match entry.external() {
|
||||||
|
External::Function(_) => idx += 1,
|
||||||
|
_ => continue,
|
||||||
|
}
|
||||||
|
if entry.module() != "__wbindgen_placeholder__" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if entry.field() != "__wbindgen_describe" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret.describe_idx = Some(idx - 1 as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build up the mapping of exported functions to function indices.
|
||||||
|
if let Some(e) = module.export_section() {
|
||||||
|
for e in e.entries() {
|
||||||
|
let i = match e.internal() {
|
||||||
|
Internal::Function(i) => i,
|
||||||
|
_ => continue,
|
||||||
|
};
|
||||||
|
ret.name_map.insert(e.field().to_string(), *i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interprets the execution of the descriptor function `func`.
|
||||||
|
///
|
||||||
|
/// This function will execute `func` in the `module` provided. Note that
|
||||||
|
/// the `module` provided here must be the same as the one passed to `new`
|
||||||
|
/// when this `Interpreter` was constructed.
|
||||||
|
///
|
||||||
|
/// The `func` must be a wasm-bindgen descriptor function meaning that it
|
||||||
|
/// doesn't do anything like use floats or i64. Instead all it should do is
|
||||||
|
/// call other functions, sometimes some stack pointer manipulation, and
|
||||||
|
/// then call the one imported `__wbindgen_describe` function. Anything else
|
||||||
|
/// will cause this interpreter to panic.
|
||||||
|
///
|
||||||
|
/// When the descriptor has finished running the assembled descriptor list
|
||||||
|
/// is returned. The descriptor returned can then be re-parsed into an
|
||||||
|
/// actual `Descriptor` in the cli-support crate.
|
||||||
|
///
|
||||||
|
/// # Return value
|
||||||
|
///
|
||||||
|
/// Returns `Some` if `func` was found in the `module` and `None` if it was
|
||||||
|
/// not found in the `module`.
|
||||||
|
pub fn interpret(&mut self, func: &str, module: &Module) -> Option<&[u32]> {
|
||||||
|
self.descriptor.truncate(0);
|
||||||
|
let idx = *self.name_map.get(func)?;
|
||||||
|
let code = match &module.sections()[self.code_idx.unwrap()] {
|
||||||
|
Section::Code(s) => s,
|
||||||
|
_ => panic!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// We should have a blank wasm and LLVM stack at both the start and end
|
||||||
|
// of the call.
|
||||||
|
assert_eq!(self.sp, self.mem.len() as i32);
|
||||||
|
assert_eq!(self.stack.len(), 0);
|
||||||
|
self.call(idx, code);
|
||||||
|
assert_eq!(self.stack.len(), 0);
|
||||||
|
assert_eq!(self.sp, self.mem.len() as i32);
|
||||||
|
Some(&self.descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&mut self, idx: u32, code: &CodeSection) {
|
||||||
|
use parity_wasm::elements::Instruction::*;
|
||||||
|
|
||||||
|
let idx = idx as usize;
|
||||||
|
assert!(idx >= self.imports); // can't call imported functions
|
||||||
|
let body = &code.bodies()[idx - self.imports];
|
||||||
|
|
||||||
|
// Allocate space for our call frame's local variables. All local
|
||||||
|
// variables should be of the `i32` type.
|
||||||
|
assert!(body.locals().len() <= 1, "too many local types");
|
||||||
|
let locals = body.locals()
|
||||||
|
.get(0)
|
||||||
|
.map(|i| {
|
||||||
|
assert_eq!(i.value_type(), ValueType::I32);
|
||||||
|
i.count()
|
||||||
|
})
|
||||||
|
.unwrap_or(0);
|
||||||
|
let mut locals = vec![0; locals as usize];
|
||||||
|
|
||||||
|
// Actual interpretation loop! We keep track of our stack's length to
|
||||||
|
// recover it as part of the `Return` instruction, and otherwise this is
|
||||||
|
// a pretty straightforward interpretation loop.
|
||||||
|
let before = self.stack.len();
|
||||||
|
for instr in body.code().elements() {
|
||||||
|
match instr {
|
||||||
|
I32Const(x) => self.stack.push(*x),
|
||||||
|
SetLocal(i) => locals[*i as usize] = self.stack.pop().unwrap(),
|
||||||
|
GetLocal(i) => self.stack.push(locals[*i as usize]),
|
||||||
|
Call(idx) => {
|
||||||
|
// If this function is calling the `__wbindgen_describe`
|
||||||
|
// function, which we've precomputed the index for, then
|
||||||
|
// it's telling us about the next `u32` element in the
|
||||||
|
// descriptor to return. We "call" the imported function
|
||||||
|
// here by directly inlining it.
|
||||||
|
//
|
||||||
|
// Otherwise this is a normal call so we recurse.
|
||||||
|
if Some(*idx) == self.describe_idx {
|
||||||
|
self.descriptor.push(self.stack.pop().unwrap() as u32);
|
||||||
|
} else {
|
||||||
|
self.call(*idx, code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GetGlobal(0) => self.stack.push(self.sp),
|
||||||
|
SetGlobal(0) => self.sp = self.stack.pop().unwrap(),
|
||||||
|
I32Sub => {
|
||||||
|
let b = self.stack.pop().unwrap();
|
||||||
|
let a = self.stack.pop().unwrap();
|
||||||
|
self.stack.push(a - b);
|
||||||
|
}
|
||||||
|
I32Add => {
|
||||||
|
let a = self.stack.pop().unwrap();
|
||||||
|
let b = self.stack.pop().unwrap();
|
||||||
|
self.stack.push(a + b);
|
||||||
|
}
|
||||||
|
I32Store(/* align = */ 2, offset) => {
|
||||||
|
let val = self.stack.pop().unwrap();
|
||||||
|
let addr = self.stack.pop().unwrap() as u32;
|
||||||
|
self.mem[((addr + *offset) as usize) / 4] = val;
|
||||||
|
}
|
||||||
|
I32Load(/* align = */ 2, offset) => {
|
||||||
|
let addr = self.stack.pop().unwrap() as u32;
|
||||||
|
self.stack.push(self.mem[((addr + *offset) as usize) / 4]);
|
||||||
|
}
|
||||||
|
Return => self.stack.truncate(before),
|
||||||
|
End => break,
|
||||||
|
|
||||||
|
// All other instructions shouldn't be used by our various
|
||||||
|
// descriptor functions. LLVM optimizations may mean that some
|
||||||
|
// of the above instructions aren't actually needed either, but
|
||||||
|
// the above instructions have empirically been required when
|
||||||
|
// executing our own test suite in wasm-bindgen.
|
||||||
|
//
|
||||||
|
// Note that LLVM may change over time to generate new
|
||||||
|
// instructions in debug mode, and we'll have to react to those
|
||||||
|
// sorts of changes as they arise.
|
||||||
|
s => panic!("unknown instruction {:?}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert_eq!(self.stack.len(), before);
|
||||||
|
}
|
||||||
|
}
|
232
crates/wasm-interpreter/tests/smoke.rs
Normal file
232
crates/wasm-interpreter/tests/smoke.rs
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
extern crate parity_wasm;
|
||||||
|
extern crate tempfile;
|
||||||
|
extern crate wasm_bindgen_wasm_interpreter;
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use wasm_bindgen_wasm_interpreter::Interpreter;
|
||||||
|
|
||||||
|
fn interpret(wat: &str, name: &str, result: Option<&[u32]>) {
|
||||||
|
let input = tempfile::NamedTempFile::new().unwrap();
|
||||||
|
let output = tempfile::NamedTempFile::new().unwrap();
|
||||||
|
fs::write(input.path(), wat).unwrap();
|
||||||
|
let status = Command::new("wat2wasm")
|
||||||
|
.arg(input.path())
|
||||||
|
.arg("-o").arg(output.path())
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
println!("status: {}", status);
|
||||||
|
assert!(status.success());
|
||||||
|
let module = parity_wasm::deserialize_file(output.path()).unwrap();
|
||||||
|
let mut i = Interpreter::new(&module);
|
||||||
|
assert_eq!(i.interpret(name, &module), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn smoke() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
|
||||||
|
(func $foo)
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[]));
|
||||||
|
interpret(wat, "bar", None);
|
||||||
|
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
i32.const 1
|
||||||
|
call $__wbindgen_describe
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn locals() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
(local i32)
|
||||||
|
i32.const 2
|
||||||
|
set_local 0
|
||||||
|
get_local 0
|
||||||
|
call $__wbindgen_describe
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn globals() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(global i32 (i32.const 0))
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
(local i32)
|
||||||
|
get_global 0
|
||||||
|
set_local 0
|
||||||
|
get_local 0
|
||||||
|
call $__wbindgen_describe
|
||||||
|
get_local 0
|
||||||
|
set_global 0
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[256]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn arithmetic() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
i32.const 1
|
||||||
|
i32.const 2
|
||||||
|
i32.add
|
||||||
|
call $__wbindgen_describe
|
||||||
|
i32.const 2
|
||||||
|
i32.const 1
|
||||||
|
i32.sub
|
||||||
|
call $__wbindgen_describe
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[3, 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_early() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
i32.const 1
|
||||||
|
i32.const 2
|
||||||
|
call $__wbindgen_describe
|
||||||
|
return
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn loads_and_stores() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(global i32 (i32.const 0))
|
||||||
|
(memory 1)
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
(local i32)
|
||||||
|
|
||||||
|
;; decrement the stack pointer, setting our local to the
|
||||||
|
;; lowest address of our stack
|
||||||
|
get_global 0
|
||||||
|
i32.const 16
|
||||||
|
i32.sub
|
||||||
|
set_local 0
|
||||||
|
get_local 0
|
||||||
|
set_global 0
|
||||||
|
|
||||||
|
;; store 1 at fp+0
|
||||||
|
get_local 0
|
||||||
|
i32.const 1
|
||||||
|
i32.store offset=0
|
||||||
|
|
||||||
|
;; store 2 at fp+4
|
||||||
|
get_local 0
|
||||||
|
i32.const 2
|
||||||
|
i32.store offset=4
|
||||||
|
|
||||||
|
;; store 3 at fp+8
|
||||||
|
get_local 0
|
||||||
|
i32.const 3
|
||||||
|
i32.store offset=8
|
||||||
|
|
||||||
|
;; load fp+0 and call
|
||||||
|
get_local 0
|
||||||
|
i32.load offset=0
|
||||||
|
call $__wbindgen_describe
|
||||||
|
|
||||||
|
;; load fp+4 and call
|
||||||
|
get_local 0
|
||||||
|
i32.load offset=4
|
||||||
|
call $__wbindgen_describe
|
||||||
|
|
||||||
|
;; load fp+8 and call
|
||||||
|
get_local 0
|
||||||
|
i32.load offset=8
|
||||||
|
call $__wbindgen_describe
|
||||||
|
|
||||||
|
;; increment our stack pointer
|
||||||
|
get_local 0
|
||||||
|
i32.const 16
|
||||||
|
i32.add
|
||||||
|
set_global 0
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[1, 2, 3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn calling_functions() {
|
||||||
|
let wat = r#"
|
||||||
|
(module
|
||||||
|
(import "__wbindgen_placeholder__" "__wbindgen_describe"
|
||||||
|
(func $__wbindgen_describe (param i32)))
|
||||||
|
|
||||||
|
(global i32 (i32.const 0))
|
||||||
|
(memory 1)
|
||||||
|
|
||||||
|
(func $foo
|
||||||
|
call $bar
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $bar
|
||||||
|
i32.const 0
|
||||||
|
call $__wbindgen_describe
|
||||||
|
)
|
||||||
|
|
||||||
|
(export "foo" (func $foo))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
interpret(wat, "foo", Some(&[0]));
|
||||||
|
}
|
@ -15,11 +15,10 @@ wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.17" }
|
|||||||
sourcefile = "0.1"
|
sourcefile = "0.1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
wasm-bindgen = { path = "../..", version = "0.2.17" }
|
wasm-bindgen = { path = "../..", version = "0.2.19" }
|
||||||
js-sys = { path = '../js-sys', version = '0.2.1' }
|
js-sys = { path = '../js-sys', version = '0.2.4' }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
js-sys = { path = '../js-sys', version = '0.2.1' }
|
wasm-bindgen-test = { path = '../test', version = '0.2.19' }
|
||||||
wasm-bindgen-test = { path = '../test', version = '0.2.17' }
|
wasm-bindgen-futures = { path = '../futures', version = '0.2.19' }
|
||||||
wasm-bindgen-futures = { path = '../futures', version = '0.2.17' }
|
|
||||||
|
@ -3,6 +3,6 @@ use web_sys::console;
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_console() {
|
fn test_console() {
|
||||||
console::time_using_label("test label");
|
console::time_with_label("test label");
|
||||||
console::time_end_using_label("test label");
|
console::time_end_with_label("test label");
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use web_sys::{DomPoint, DomPointReadOnly};
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn dom_point() {
|
fn dom_point() {
|
||||||
let x = DomPoint::new_using_x_and_y_and_z_and_w(1.0, 2.0, 3.0, 4.0).unwrap();
|
let x = DomPoint::new_with_x_and_y_and_z_and_w(1.0, 2.0, 3.0, 4.0).unwrap();
|
||||||
assert_eq!(x.x(), 1.0);
|
assert_eq!(x.x(), 1.0);
|
||||||
x.set_x(1.5);
|
x.set_x(1.5);
|
||||||
assert_eq!(x.x(), 1.5);
|
assert_eq!(x.x(), 1.5);
|
||||||
@ -24,7 +24,7 @@ fn dom_point() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn dom_point_readonly() {
|
fn dom_point_readonly() {
|
||||||
let x = DomPoint::new_using_x_and_y_and_z_and_w(1.0, 2.0, 3.0, 4.0).unwrap();
|
let x = DomPoint::new_with_x_and_y_and_z_and_w(1.0, 2.0, 3.0, 4.0).unwrap();
|
||||||
let x = DomPointReadOnly::from(JsValue::from(x));
|
let x = DomPointReadOnly::from(JsValue::from(x));
|
||||||
assert_eq!(x.x(), 1.0);
|
assert_eq!(x.x(), 1.0);
|
||||||
assert_eq!(x.y(), 2.0);
|
assert_eq!(x.y(), 2.0);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
#![cfg(target_arch = "wasm32")]
|
#![cfg(target_arch = "wasm32")]
|
||||||
|
|
||||||
extern crate futures;
|
extern crate futures;
|
||||||
|
@ -3,7 +3,7 @@ use web_sys::HtmlOptionElement;
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn test_option_element() {
|
fn test_option_element() {
|
||||||
let option = HtmlOptionElement::new_using_text_and_value_and_default_selected_and_selected(
|
let option = HtmlOptionElement::new_with_text_and_value_and_default_selected_and_selected(
|
||||||
"option_text",
|
"option_text",
|
||||||
"option_value",
|
"option_value",
|
||||||
false,
|
false,
|
||||||
|
@ -99,7 +99,7 @@ fn test_table_element() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
table
|
table
|
||||||
.insert_row_using_index(0)
|
.insert_row_with_index(0)
|
||||||
.expect("Failed to insert row at index 0");
|
.expect("Failed to insert row at index 0");
|
||||||
assert!(
|
assert!(
|
||||||
table.rows().length() == 1,
|
table.rows().length() == 1,
|
||||||
|
@ -43,25 +43,25 @@ interface mixin WindowOrWorkerGlobalScope {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// https://fetch.spec.whatwg.org/#fetch-method
|
// https://fetch.spec.whatwg.org/#fetch-method
|
||||||
partial interface WindowOrWorkerGlobalScope {
|
partial interface mixin WindowOrWorkerGlobalScope {
|
||||||
[NewObject, NeedsCallerType]
|
[NewObject, NeedsCallerType]
|
||||||
Promise<Response> fetch(RequestInfo input, optional RequestInit init);
|
Promise<Response> fetch(RequestInfo input, optional RequestInit init);
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
|
// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
|
||||||
partial interface WindowOrWorkerGlobalScope {
|
partial interface mixin WindowOrWorkerGlobalScope {
|
||||||
readonly attribute boolean isSecureContext;
|
readonly attribute boolean isSecureContext;
|
||||||
};
|
};
|
||||||
|
|
||||||
// http://w3c.github.io/IndexedDB/#factory-interface
|
// http://w3c.github.io/IndexedDB/#factory-interface
|
||||||
partial interface WindowOrWorkerGlobalScope {
|
partial interface mixin WindowOrWorkerGlobalScope {
|
||||||
// readonly attribute IDBFactory indexedDB;
|
// readonly attribute IDBFactory indexedDB;
|
||||||
[Throws]
|
[Throws]
|
||||||
readonly attribute IDBFactory? indexedDB;
|
readonly attribute IDBFactory? indexedDB;
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://w3c.github.io/ServiceWorker/#self-caches
|
// https://w3c.github.io/ServiceWorker/#self-caches
|
||||||
partial interface WindowOrWorkerGlobalScope {
|
partial interface mixin WindowOrWorkerGlobalScope {
|
||||||
[Throws, Func="mozilla::dom::DOMPrefs::DOMCachesEnabled", SameObject]
|
[Throws, Func="mozilla::dom::DOMPrefs::DOMCachesEnabled", SameObject]
|
||||||
readonly attribute CacheStorage caches;
|
readonly attribute CacheStorage caches;
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,6 @@ fn take_and_return_a_bunch_of_slices() {
|
|||||||
assert_eq!(f.i16(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.i16(&[1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.i32(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.i32(&[1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.u8(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.u8(&[1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.u8_clamped(&[1, 2]), [3, 4, 5]);
|
|
||||||
assert_eq!(f.u16(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.u16(&[1, 2]), [3, 4, 5]);
|
||||||
assert_eq!(f.u32(&[1, 2]), [3, 4, 5]);
|
assert_eq!(f.u32(&[1, 2]), [3, 4, 5]);
|
||||||
}
|
}
|
||||||
|
4
crates/webidl-tests/global.js
Normal file
4
crates/webidl-tests/global.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
global.global_no_args = () => 3;
|
||||||
|
global.global_with_args = (a, b) => a + b;
|
||||||
|
global.global_attribute = 'x';
|
||||||
|
|
12
crates/webidl-tests/global.rs
Normal file
12
crates/webidl-tests/global.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/global.rs"));
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
fn works() {
|
||||||
|
assert_eq!(Global::global_no_args(), 3);
|
||||||
|
assert_eq!(Global::global_with_args("a", "b"), "ab");
|
||||||
|
assert_eq!(Global::global_attribute(), "x");
|
||||||
|
Global::set_global_attribute("y");
|
||||||
|
assert_eq!(Global::global_attribute(), "y");
|
||||||
|
}
|
6
crates/webidl-tests/global.webidl
vendored
Normal file
6
crates/webidl-tests/global.webidl
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[Global=x]
|
||||||
|
interface Global {
|
||||||
|
unsigned long global_no_args();
|
||||||
|
DOMString global_with_args(DOMString a, DOMString b);
|
||||||
|
attribute DOMString global_attribute;
|
||||||
|
};
|
@ -1,5 +1,3 @@
|
|||||||
#![feature(use_extern_macros)]
|
|
||||||
|
|
||||||
extern crate js_sys;
|
extern crate js_sys;
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
extern crate wasm_bindgen_test;
|
extern crate wasm_bindgen_test;
|
||||||
@ -12,3 +10,4 @@ pub mod namespace;
|
|||||||
pub mod simple;
|
pub mod simple;
|
||||||
pub mod throws;
|
pub mod throws;
|
||||||
pub mod dictionary;
|
pub mod dictionary;
|
||||||
|
pub mod global;
|
||||||
|
@ -87,11 +87,7 @@ global.Unforgeable = class Unforgeable {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
global.GlobalMethod = class GlobalMethod {
|
global.m = () => 123;
|
||||||
constructor() {
|
|
||||||
this.m = () => 123;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
global.Indexing = function () {
|
global.Indexing = function () {
|
||||||
return new Proxy({}, {
|
return new Proxy({}, {
|
||||||
|
@ -50,7 +50,7 @@ fn static_property() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn one_method_using_an_undefined_import_doesnt_break_all_other_methods() {
|
fn one_method_with_an_undefined_import_doesnt_break_all_other_methods() {
|
||||||
let f = UndefinedMethod::new().unwrap();
|
let f = UndefinedMethod::new().unwrap();
|
||||||
assert!(f.ok_method());
|
assert!(f.ok_method());
|
||||||
}
|
}
|
||||||
@ -64,8 +64,7 @@ fn nullable_method() {
|
|||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn global_method() {
|
fn global_method() {
|
||||||
let f = GlobalMethod::new().unwrap();
|
assert_eq!(GlobalMethod::m(), 123);
|
||||||
assert_eq!(f.m(), 123);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
@ -81,14 +80,14 @@ fn indexing() {
|
|||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn optional_and_union_arguments() {
|
fn optional_and_union_arguments() {
|
||||||
let f = OptionalAndUnionArguments::new().unwrap();
|
let f = OptionalAndUnionArguments::new().unwrap();
|
||||||
assert_eq!(f.m_using_a("abc"), "string, abc, boolean, true, number, 123, number, 456");
|
assert_eq!(f.m("abc"), "string, abc, boolean, true, number, 123, number, 456");
|
||||||
assert_eq!(f.m_using_a_and_b("abc", false), "string, abc, boolean, false, number, 123, number, 456");
|
assert_eq!(f.m_with_b("abc", false), "string, abc, boolean, false, number, 123, number, 456");
|
||||||
assert_eq!(f.m_using_dom_str_and_bool_and_i16("abc", false, 5), "string, abc, boolean, false, number, 5, number, 456");
|
assert_eq!(f.m_with_bool_and_i16("abc", false, 5), "string, abc, boolean, false, number, 5, number, 456");
|
||||||
assert_eq!(f.m_using_dom_str_and_bool_and_dom_str("abc", false, "5"), "string, abc, boolean, false, string, 5, number, 456");
|
assert_eq!(f.m_with_bool_and_str("abc", false, "5"), "string, abc, boolean, false, string, 5, number, 456");
|
||||||
assert_eq!(f.m_using_dom_str_and_bool_and_i16_and_opt_i64("abc", false, 5, Some(10)), "string, abc, boolean, false, number, 5, bigint, 10");
|
assert_eq!(f.m_with_bool_and_i16_and_opt_i64("abc", false, 5, Some(10)), "string, abc, boolean, false, number, 5, bigint, 10");
|
||||||
assert_eq!(f.m_using_dom_str_and_bool_and_i16_and_opt_bool("abc", false, 5, Some(true)), "string, abc, boolean, false, number, 5, boolean, true");
|
assert_eq!(f.m_with_bool_and_i16_and_opt_bool("abc", false, 5, Some(true)), "string, abc, boolean, false, number, 5, boolean, true");
|
||||||
assert_eq!(f.m_using_dom_str_and_bool_and_dom_str_and_opt_i64("abc", false, "5", Some(10)), "string, abc, boolean, false, string, 5, bigint, 10");
|
assert_eq!(f.m_with_bool_and_str_and_opt_i64("abc", false, "5", Some(10)), "string, abc, boolean, false, string, 5, bigint, 10");
|
||||||
assert_eq!(f.m_using_dom_str_and_bool_and_dom_str_and_opt_bool("abc", false, "5", Some(true)), "string, abc, boolean, false, string, 5, boolean, true");
|
assert_eq!(f.m_with_bool_and_str_and_opt_bool("abc", false, "5", Some(true)), "string, abc, boolean, false, string, 5, boolean, true");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
|
@ -19,5 +19,5 @@ log = "0.4.1"
|
|||||||
proc-macro2 = "0.4.8"
|
proc-macro2 = "0.4.8"
|
||||||
quote = '0.6'
|
quote = '0.6'
|
||||||
syn = { version = '0.14', features = ['full'] }
|
syn = { version = '0.14', features = ['full'] }
|
||||||
wasm-bindgen-backend = { version = "=0.2.17", path = "../backend" }
|
wasm-bindgen-backend = { version = "=0.2.19", path = "../backend" }
|
||||||
weedle = "0.6"
|
weedle = "0.6"
|
||||||
|
@ -348,13 +348,13 @@ impl<'a> IdlType<'a> {
|
|||||||
IdlType::UnsignedLong => dst.push_str("u32"),
|
IdlType::UnsignedLong => dst.push_str("u32"),
|
||||||
IdlType::LongLong => dst.push_str("i64"),
|
IdlType::LongLong => dst.push_str("i64"),
|
||||||
IdlType::UnsignedLongLong => dst.push_str("u64"),
|
IdlType::UnsignedLongLong => dst.push_str("u64"),
|
||||||
IdlType::Float => dst.push_str("f32"),
|
IdlType::Float |
|
||||||
IdlType::UnrestrictedFloat => dst.push_str("unrestricted_f32"),
|
IdlType::UnrestrictedFloat => dst.push_str("f32"),
|
||||||
IdlType::Double => dst.push_str("f64"),
|
IdlType::Double |
|
||||||
IdlType::UnrestrictedDouble => dst.push_str("unrestricted_f64"),
|
IdlType::UnrestrictedDouble => dst.push_str("f64"),
|
||||||
IdlType::DomString => dst.push_str("dom_str"),
|
IdlType::DomString |
|
||||||
IdlType::ByteString => dst.push_str("byte_str"),
|
IdlType::ByteString |
|
||||||
IdlType::UsvString => dst.push_str("usv_str"),
|
IdlType::UsvString => dst.push_str("str"),
|
||||||
IdlType::Object => dst.push_str("object"),
|
IdlType::Object => dst.push_str("object"),
|
||||||
IdlType::Symbol => dst.push_str("symbol"),
|
IdlType::Symbol => dst.push_str("symbol"),
|
||||||
IdlType::Error => dst.push_str("error"),
|
IdlType::Error => dst.push_str("error"),
|
||||||
@ -459,7 +459,7 @@ impl<'a> IdlType<'a> {
|
|||||||
IdlType::DataView => None,
|
IdlType::DataView => None,
|
||||||
IdlType::Int8Array => Some(array("i8", pos)),
|
IdlType::Int8Array => Some(array("i8", pos)),
|
||||||
IdlType::Uint8Array => Some(array("u8", pos)),
|
IdlType::Uint8Array => Some(array("u8", pos)),
|
||||||
IdlType::Uint8ClampedArray => Some(array("u8", pos)),
|
IdlType::Uint8ClampedArray => None, // FIXME(#421)
|
||||||
IdlType::Int16Array => Some(array("i16", pos)),
|
IdlType::Int16Array => Some(array("i16", pos)),
|
||||||
IdlType::Uint16Array => Some(array("u16", pos)),
|
IdlType::Uint16Array => Some(array("u16", pos)),
|
||||||
IdlType::Int32Array => Some(array("i32", pos)),
|
IdlType::Int32Array => Some(array("i32", pos)),
|
||||||
|
@ -591,6 +591,11 @@ fn member_attribute<'src>(
|
|||||||
|
|
||||||
let is_structural = util::is_structural(attrs);
|
let is_structural = util::is_structural(attrs);
|
||||||
let throws = util::throws(attrs);
|
let throws = util::throws(attrs);
|
||||||
|
let global = first_pass
|
||||||
|
.interfaces
|
||||||
|
.get(self_name)
|
||||||
|
.map(|interface_data| interface_data.global)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
for import_function in first_pass.create_getter(
|
for import_function in first_pass.create_getter(
|
||||||
identifier,
|
identifier,
|
||||||
@ -599,6 +604,7 @@ fn member_attribute<'src>(
|
|||||||
is_static,
|
is_static,
|
||||||
is_structural,
|
is_structural,
|
||||||
throws,
|
throws,
|
||||||
|
global,
|
||||||
) {
|
) {
|
||||||
program.imports.push(wrap_import_function(import_function));
|
program.imports.push(wrap_import_function(import_function));
|
||||||
}
|
}
|
||||||
@ -611,6 +617,7 @@ fn member_attribute<'src>(
|
|||||||
is_static,
|
is_static,
|
||||||
is_structural,
|
is_structural,
|
||||||
throws,
|
throws,
|
||||||
|
global,
|
||||||
) {
|
) {
|
||||||
program.imports.push(wrap_import_function(import_function));
|
program.imports.push(wrap_import_function(import_function));
|
||||||
}
|
}
|
||||||
@ -712,6 +719,12 @@ fn member_operation<'src>(
|
|||||||
operation_ids.push(id);
|
operation_ids.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let global = first_pass
|
||||||
|
.interfaces
|
||||||
|
.get(self_name)
|
||||||
|
.map(|interface_data| interface_data.global)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
for id in operation_ids {
|
for id in operation_ids {
|
||||||
let methods = first_pass
|
let methods = first_pass
|
||||||
.create_basic_method(
|
.create_basic_method(
|
||||||
@ -724,15 +737,10 @@ fn member_operation<'src>(
|
|||||||
OperationId::IndexingGetter |
|
OperationId::IndexingGetter |
|
||||||
OperationId::IndexingSetter |
|
OperationId::IndexingSetter |
|
||||||
OperationId::IndexingDeleter => true,
|
OperationId::IndexingDeleter => true,
|
||||||
_ => {
|
_ => false,
|
||||||
first_pass
|
|
||||||
.interfaces
|
|
||||||
.get(self_name)
|
|
||||||
.map(|interface_data| interface_data.global)
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
util::throws(attrs),
|
util::throws(attrs),
|
||||||
|
global,
|
||||||
);
|
);
|
||||||
|
|
||||||
for method in methods {
|
for method in methods {
|
||||||
|
@ -273,9 +273,13 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
let rust_name = if possibilities.len() > 1 {
|
let rust_name = if possibilities.len() > 1 {
|
||||||
let mut rust_name = rust_name.clone();
|
let mut rust_name = rust_name.clone();
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
for ((argument_name, _, _), idl_type) in arguments.iter().zip(idl_types) {
|
let iter = arguments.iter().zip(idl_types).enumerate();
|
||||||
|
for (i, ((argument_name, _, _), idl_type)) in iter {
|
||||||
|
if possibilities.iter().all(|p| p.get(i) == Some(idl_type)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if first {
|
if first {
|
||||||
rust_name.push_str("_using_");
|
rust_name.push_str("_with_");
|
||||||
first = false;
|
first = false;
|
||||||
} else {
|
} else {
|
||||||
rust_name.push_str("_and_");
|
rust_name.push_str("_and_");
|
||||||
@ -293,6 +297,7 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
let rust_name = rust_ident(&rust_name);
|
let rust_name = rust_ident(&rust_name);
|
||||||
let shim = {
|
let shim = {
|
||||||
let ns = match kind {
|
let ns = match kind {
|
||||||
|
backend::ast::ImportFunctionKind::ScopedMethod { .. } |
|
||||||
backend::ast::ImportFunctionKind::Normal => "",
|
backend::ast::ImportFunctionKind::Normal => "",
|
||||||
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
||||||
};
|
};
|
||||||
@ -386,6 +391,7 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
is_static: bool,
|
is_static: bool,
|
||||||
structural: bool,
|
structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
|
global: bool,
|
||||||
) -> Vec<backend::ast::ImportFunction> {
|
) -> Vec<backend::ast::ImportFunction> {
|
||||||
let (overloaded, same_argument_names) = self.get_operation_overloading(
|
let (overloaded, same_argument_names) = self.get_operation_overloading(
|
||||||
arguments,
|
arguments,
|
||||||
@ -407,20 +413,26 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
first_pass::OperationId::IndexingSetter => "set",
|
first_pass::OperationId::IndexingSetter => "set",
|
||||||
first_pass::OperationId::IndexingDeleter => "delete",
|
first_pass::OperationId::IndexingDeleter => "delete",
|
||||||
};
|
};
|
||||||
|
let operation_kind = match &operation_id {
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
||||||
class: self_name.to_string(),
|
first_pass::OperationId::Operation(_) => backend::ast::OperationKind::Regular,
|
||||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
first_pass::OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
first_pass::OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
|
||||||
is_static,
|
first_pass::OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
|
||||||
kind: match &operation_id {
|
};
|
||||||
first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
let operation = backend::ast::Operation { is_static, kind: operation_kind };
|
||||||
first_pass::OperationId::Operation(_) => backend::ast::OperationKind::Regular,
|
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
||||||
first_pass::OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
|
let kind = if global {
|
||||||
first_pass::OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
|
backend::ast::ImportFunctionKind::ScopedMethod {
|
||||||
first_pass::OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
|
ty,
|
||||||
},
|
operation,
|
||||||
}),
|
}
|
||||||
|
} else {
|
||||||
|
backend::ast::ImportFunctionKind::Method {
|
||||||
|
class: self_name.to_string(),
|
||||||
|
ty,
|
||||||
|
kind: backend::ast::MethodKind::Operation(operation),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = match return_type.to_idl_type(self) {
|
let ret = match return_type.to_idl_type(self) {
|
||||||
@ -588,19 +600,29 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
is_static: bool,
|
is_static: bool,
|
||||||
is_structural: bool,
|
is_structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
|
global: bool,
|
||||||
) -> Vec<backend::ast::ImportFunction> {
|
) -> Vec<backend::ast::ImportFunction> {
|
||||||
let ret = match ty.to_idl_type(self) {
|
let ret = match ty.to_idl_type(self) {
|
||||||
None => return Vec::new(),
|
None => return Vec::new(),
|
||||||
Some(idl_type) => idl_type,
|
Some(idl_type) => idl_type,
|
||||||
};
|
};
|
||||||
|
let operation = backend::ast::Operation {
|
||||||
|
is_static,
|
||||||
|
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
||||||
|
};
|
||||||
|
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
||||||
|
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let kind = if global {
|
||||||
class: self_name.to_string(),
|
backend::ast::ImportFunctionKind::ScopedMethod {
|
||||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
ty,
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
operation,
|
||||||
is_static,
|
}
|
||||||
kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))),
|
} else {
|
||||||
}),
|
backend::ast::ImportFunctionKind::Method {
|
||||||
|
class: self_name.to_string(),
|
||||||
|
ty,
|
||||||
|
kind: backend::ast::MethodKind::Operation(operation),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
||||||
|
|
||||||
@ -611,19 +633,30 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
pub fn create_setter(
|
pub fn create_setter(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
ty: weedle::types::Type,
|
field_ty: weedle::types::Type,
|
||||||
self_name: &str,
|
self_name: &str,
|
||||||
is_static: bool,
|
is_static: bool,
|
||||||
is_structural: bool,
|
is_structural: bool,
|
||||||
catch: bool,
|
catch: bool,
|
||||||
|
global: bool,
|
||||||
) -> Vec<backend::ast::ImportFunction> {
|
) -> Vec<backend::ast::ImportFunction> {
|
||||||
let kind = backend::ast::ImportFunctionKind::Method {
|
let operation = backend::ast::Operation {
|
||||||
class: self_name.to_string(),
|
is_static,
|
||||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
||||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
};
|
||||||
is_static,
|
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
||||||
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
|
||||||
}),
|
let kind = if global {
|
||||||
|
backend::ast::ImportFunctionKind::ScopedMethod {
|
||||||
|
ty,
|
||||||
|
operation,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
backend::ast::ImportFunctionKind::Method {
|
||||||
|
class: self_name.to_string(),
|
||||||
|
ty,
|
||||||
|
kind: backend::ast::MethodKind::Operation(operation),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let doc_comment = Some(format!("The `{}` setter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
let doc_comment = Some(format!("The `{}` setter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
||||||
|
|
||||||
@ -633,7 +666,7 @@ impl<'src> FirstPassRecord<'src> {
|
|||||||
false,
|
false,
|
||||||
&[(
|
&[(
|
||||||
name,
|
name,
|
||||||
match ty.to_idl_type(self) {
|
match field_ty.to_idl_type(self) {
|
||||||
None => return Vec::new(),
|
None => return Vec::new(),
|
||||||
Some(idl_type) => idl_type,
|
Some(idl_type) => idl_type,
|
||||||
},
|
},
|
||||||
|
@ -10,31 +10,33 @@ when using `build.sh`!
|
|||||||
|
|
||||||
The examples here are:
|
The examples here are:
|
||||||
|
|
||||||
* `hello_world` - the "hello world" of `#[wasm_bindgen]`, aka throwing up a
|
|
||||||
dialog greeting you
|
|
||||||
* `console_log` - a showcase of `#[wasm_bindgen]` importing classes and how to
|
|
||||||
bind `console.log`
|
|
||||||
* `math` - like `console_log` except showing how to import Math-related
|
|
||||||
functions instead
|
|
||||||
* `dom` - an example of accessing the global `document` object and appending
|
|
||||||
HTML to it
|
|
||||||
* `smorgasboard` - a bunch of features all thrown into one, showing off the
|
|
||||||
various capabilities of the `#[wasm_bindgen]` macro and what you can do with
|
|
||||||
it from JS
|
|
||||||
* `performance` - how to import APIs like `performance.now()` and time various
|
|
||||||
operations in Rust
|
|
||||||
* `wasm-in-wasm` - how to interact with namespaced APIs like
|
|
||||||
`WebAssembly.Module` and shows off creation of a WebAssembly module from Rust
|
|
||||||
* `closures` - an example of how to invoke functions like `setInterval` or use
|
|
||||||
the `onclick` property in conjunction with closures.
|
|
||||||
* `no_modules` - an example of how to use the `--no-modules` flag to
|
|
||||||
the `wasm-bindgen` CLI tool
|
|
||||||
* `add` - an example of generating a tiny wasm binary, one that only adds two
|
* `add` - an example of generating a tiny wasm binary, one that only adds two
|
||||||
numbers.
|
numbers.
|
||||||
* `asm.js` - an example of using the `wasm2asm` tool from [binaryen] to convert
|
* `asm.js` - an example of using the `wasm2asm` tool from [binaryen] to convert
|
||||||
the generated WebAssembly to normal JS
|
the generated WebAssembly to normal JS
|
||||||
* `char` - an example of passing the rust `char` type to and from the js `string` type
|
* `char` - an example of passing the rust `char` type to and from the js `string` type
|
||||||
* `import_js` - an example of importing local JS functionality into a crate
|
* `closures` - an example of how to invoke functions like `setInterval` or use
|
||||||
|
the `onclick` property in conjunction with closures.
|
||||||
* `comments` - an example of how Rust comments are copied into js bindings
|
* `comments` - an example of how Rust comments are copied into js bindings
|
||||||
|
* `console_log` - a showcase of `#[wasm_bindgen]` importing classes and how to
|
||||||
|
bind `console.log`
|
||||||
|
* `dom` - an example of accessing the global `document` object and appending
|
||||||
|
HTML to it
|
||||||
|
* `fetch` -- how to use the Fetch API to make async http requests
|
||||||
|
* `hello_world` - the "hello world" of `#[wasm_bindgen]`, aka throwing up a
|
||||||
|
dialog greeting you
|
||||||
|
* `import_js` - an example of importing local JS functionality into a crate
|
||||||
|
* `math` - like `console_log` except showing how to import Math-related
|
||||||
|
functions instead
|
||||||
|
* `no_modules` - an example of how to use the `--no-modules` flag to
|
||||||
|
the `wasm-bindgen` CLI tool
|
||||||
|
* `performance` - how to import APIs like `performance.now()` and time various
|
||||||
|
operations in Rust
|
||||||
|
* `smorgasboard` - a bunch of features all thrown into one, showing off the
|
||||||
|
various capabilities of the `#[wasm_bindgen]` macro and what you can do with
|
||||||
|
it from JS
|
||||||
|
* `wasm-in-wasm` - how to interact with namespaced APIs like
|
||||||
|
`WebAssembly.Module` and shows off creation of a WebAssembly module from Rust
|
||||||
|
* `webaudio` - how to use the Web Audio APIs to generate sounds
|
||||||
|
|
||||||
[binaryen]: https://github.com/WebAssembly/binaryen
|
[binaryen]: https://github.com/WebAssembly/binaryen
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user