mirror of
https://github.com/rustwasm/wasm-bindgen.git
synced 2024-11-24 06:33:33 +03:00
Merge branch 'master' into variadic_js_functions
This commit is contained in:
commit
ce1cb84327
@ -19,7 +19,7 @@ build: false
|
||||
|
||||
test_script:
|
||||
- rustup target add wasm32-unknown-unknown
|
||||
- npm ci
|
||||
- npm install
|
||||
- cargo test
|
||||
- cargo build --release -p wasm-bindgen-cli
|
||||
- where chromedriver
|
||||
@ -31,6 +31,7 @@ test_script:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /^\d/
|
||||
|
||||
before_deploy:
|
||||
- ps: |
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,3 +7,5 @@ package-lock.json
|
||||
npm-shrinkwrap.json
|
||||
yarn.lock
|
||||
*.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
|
||||
|
|
||||
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
|
||||
source ~/.nvm/nvm.sh
|
||||
nvm install v10.5
|
||||
@ -56,6 +57,7 @@ matrix:
|
||||
- cargo test
|
||||
# Run the main body of the test suite
|
||||
- cargo test --target wasm32-unknown-unknown
|
||||
- cargo test --target wasm32-unknown-unknown --features nightly
|
||||
# Rerun the test suite but disable `--debug` in generated JS
|
||||
- WASM_BINDGEN_NO_DEBUG=1 cargo test --target wasm32-unknown-unknown
|
||||
# Make sure our serde tests work
|
||||
@ -74,7 +76,7 @@ matrix:
|
||||
env: JOB=examples-build
|
||||
install:
|
||||
- *INSTALL_NODE_VIA_NVM
|
||||
- npm ci --verbose
|
||||
- npm install
|
||||
script:
|
||||
- |
|
||||
for dir in `ls examples | grep -v README | grep -v asm.js | grep -v no_modules`; do
|
||||
@ -118,18 +120,6 @@ matrix:
|
||||
chrome: stable
|
||||
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
|
||||
- rust: nightly
|
||||
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
|
||||
|
||||
Released 2018-08-16.
|
||||
|
18
Cargo.toml
18
Cargo.toml
@ -1,8 +1,12 @@
|
||||
[package]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
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"
|
||||
categories = ["wasm"]
|
||||
repository = "https://github.com/rustwasm/wasm-bindgen"
|
||||
@ -21,21 +25,23 @@ default = ["spans", "std"]
|
||||
spans = ["wasm-bindgen-macro/spans"]
|
||||
std = []
|
||||
serde-serialize = ["serde", "serde_json", "std"]
|
||||
nightly = []
|
||||
|
||||
# This is only for debugging wasm-bindgen! No stability guarantees, so enable
|
||||
# this at your own peril!
|
||||
xxx_debug_only_print_generated_code = ["wasm-bindgen-macro/xxx_debug_only_print_generated_code"]
|
||||
|
||||
[dependencies]
|
||||
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_json = { version = "1.0", optional = true }
|
||||
|
||||
[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"
|
||||
wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
|
||||
wasm-bindgen-test-crate-b = { path = 'tests/crates/b' }
|
||||
wasm-bindgen-test-crate-a = { path = 'tests/crates/a', version = '0.1' }
|
||||
wasm-bindgen-test-crate-b = { path = 'tests/crates/b', version = '0.1' }
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
@ -56,6 +62,7 @@ members = [
|
||||
"examples/comments",
|
||||
"examples/console_log",
|
||||
"examples/dom",
|
||||
"examples/fetch",
|
||||
"examples/guide-supported-types-examples",
|
||||
"examples/hello_world",
|
||||
"examples/import_js",
|
||||
@ -65,6 +72,7 @@ members = [
|
||||
"examples/performance",
|
||||
"examples/smorgasboard",
|
||||
"examples/wasm-in-wasm",
|
||||
"examples/webaudio",
|
||||
"tests/no-std",
|
||||
]
|
||||
|
||||
|
23
README.md
23
README.md
@ -13,8 +13,6 @@
|
||||
Import JavaScript things into Rust and export Rust things to JavaScript.
|
||||
|
||||
```rust
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
@ -40,6 +38,27 @@ import { greet } from "./hello_world";
|
||||
greet("World!");
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
* **Lightweight.** Only pay for what you use. `wasm-bindgen` only generates
|
||||
bindings and glue for the JavaScript imports you actually use and Rust
|
||||
functionality that you export. For example, importing and using the
|
||||
`document.querySelector` method doesn't cause `Node.prototype.appendChild` or
|
||||
`window.alert` to be included in the bindings as well.
|
||||
|
||||
* **ECMAScript modules.** Just import WebAssembly modules the same way you would
|
||||
import JavaScript modules. Future compatible with [WebAssembly modules and
|
||||
ECMAScript modules integration][wasm-es-modules].
|
||||
|
||||
* **Designed with the ["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
|
||||
|
||||
[📚 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]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend"
|
||||
@ -11,7 +11,7 @@ Backend code generation of the wasm-bindgen tool
|
||||
"""
|
||||
|
||||
[features]
|
||||
spans = ["proc-macro2/nightly"]
|
||||
spans = []
|
||||
extra-traits = ["syn/extra-traits"]
|
||||
|
||||
[dependencies]
|
||||
@ -21,4 +21,4 @@ proc-macro2 = "0.4.8"
|
||||
quote = '0.6'
|
||||
serde_json = "1.0"
|
||||
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,
|
||||
kind: MethodKind,
|
||||
},
|
||||
ScopedMethod {
|
||||
ty: syn::Type,
|
||||
operation: Operation,
|
||||
},
|
||||
Normal,
|
||||
}
|
||||
|
||||
@ -408,6 +412,29 @@ impl 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 {
|
||||
ImportFunctionKind::Method {
|
||||
ref class,
|
||||
@ -416,34 +443,21 @@ impl ImportFunction {
|
||||
} => {
|
||||
let kind = match kind {
|
||||
MethodKind::Constructor => shared::MethodKind::Constructor,
|
||||
MethodKind::Operation(Operation { is_static, kind }) => {
|
||||
let is_static = *is_static;
|
||||
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 })
|
||||
MethodKind::Operation(op) => {
|
||||
shared::MethodKind::Operation(shared_operation(op))
|
||||
}
|
||||
};
|
||||
Some(shared::MethodData {
|
||||
class: class.clone(),
|
||||
class: Some(class.clone()),
|
||||
kind,
|
||||
})
|
||||
}
|
||||
ImportFunctionKind::ScopedMethod { ref operation, .. } => {
|
||||
Some(shared::MethodData {
|
||||
class: None,
|
||||
kind: shared::MethodKind::Operation(shared_operation(operation)),
|
||||
})
|
||||
}
|
||||
ImportFunctionKind::Normal => None,
|
||||
};
|
||||
|
||||
|
@ -618,9 +618,6 @@ impl ToTokens for ast::ImportType {
|
||||
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 {
|
||||
fn from(obj: #rust_name) -> JsValue {
|
||||
@ -656,12 +653,6 @@ impl ToTokens for ast::ImportType {
|
||||
// wrapper around `val`
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -800,6 +784,9 @@ impl TryToTokens for ast::ImportFunction {
|
||||
}
|
||||
class_ty = Some(ty);
|
||||
}
|
||||
ast::ImportFunctionKind::ScopedMethod { ref ty, .. } => {
|
||||
class_ty = Some(ty);
|
||||
}
|
||||
ast::ImportFunctionKind::Normal => {}
|
||||
}
|
||||
let vis = &self.function.rust_vis;
|
||||
@ -1191,9 +1178,6 @@ impl ToTokens for ast::Dictionary {
|
||||
impl AsRef<JsValue> for #name {
|
||||
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
|
||||
impl WasmDescribe for #name {
|
||||
@ -1257,10 +1241,6 @@ impl ToTokens for ast::Dictionary {
|
||||
fn unchecked_from_js_ref(val: &JsValue) -> &Self {
|
||||
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);
|
||||
|
@ -246,6 +246,7 @@ impl ImportedTypes for ast::ImportFunctionKind {
|
||||
{
|
||||
match self {
|
||||
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
|
||||
ast::ImportFunctionKind::ScopedMethod { ty, .. } => ty.imported_types(f),
|
||||
ast::ImportFunctionKind::Normal => {}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-cli-support"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
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]
|
||||
base64 = "0.9"
|
||||
failure = "0.1.2"
|
||||
parity-wasm = "0.31"
|
||||
parity-wasm = "0.32"
|
||||
serde = "1.0"
|
||||
serde_json = "1.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"
|
||||
wasmi = "0.3"
|
||||
|
@ -94,7 +94,7 @@ pub enum VectorKind {
|
||||
impl Descriptor {
|
||||
pub fn decode(mut data: &[u32]) -> Descriptor {
|
||||
let descriptor = Descriptor::_decode(&mut data);
|
||||
assert!(data.is_empty());
|
||||
assert!(data.is_empty(), "remaining data {:?}", data);
|
||||
descriptor
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ use wasm_gc;
|
||||
|
||||
use super::Bindgen;
|
||||
use descriptor::{Descriptor, VectorKind};
|
||||
use wasm_interpreter::Interpreter;
|
||||
|
||||
mod js2rust;
|
||||
use self::js2rust::Js2Rust;
|
||||
@ -23,6 +24,8 @@ pub struct Context<'a> {
|
||||
pub typescript: String,
|
||||
pub exposed_globals: 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 module: &'a mut Module,
|
||||
|
||||
@ -41,7 +44,8 @@ pub struct Context<'a> {
|
||||
|
||||
pub exported_classes: HashMap<String, ExportedClass>,
|
||||
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)]
|
||||
@ -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.gc()?;
|
||||
|
||||
@ -490,6 +507,39 @@ impl<'a> Context<'a> {
|
||||
let mut dst = format!("class {} {{\n", name);
|
||||
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() {
|
||||
self.expose_constructor_token();
|
||||
|
||||
@ -516,9 +566,11 @@ impl<'a> Context<'a> {
|
||||
// This invocation of new will call this constructor with a ConstructorToken
|
||||
let instance = {class}.{constructor}(...args);
|
||||
this.ptr = instance.ptr;
|
||||
{mkweakref}
|
||||
",
|
||||
class = name,
|
||||
constructor = constructor
|
||||
constructor = constructor,
|
||||
mkweakref = mkweakref,
|
||||
));
|
||||
} else {
|
||||
dst.push_str(
|
||||
@ -537,9 +589,11 @@ impl<'a> Context<'a> {
|
||||
|
||||
constructor(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!(
|
||||
"
|
||||
free() {{
|
||||
const ptr = this.ptr;
|
||||
this.ptr = 0;
|
||||
wasm.{}(ptr);
|
||||
free{}(ptr);
|
||||
}}
|
||||
",
|
||||
shared::free_function(&name)
|
||||
name,
|
||||
));
|
||||
ts_dst.push_str("free(): void;\n");
|
||||
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) {
|
||||
for (name, contents) in self._rewrite_imports(module_name) {
|
||||
self.export(&name, &contents, None);
|
||||
@ -666,6 +745,15 @@ impl<'a> Context<'a> {
|
||||
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 mut bind_math = |expr: &str| {
|
||||
math_imports.push((renamed_import.clone(), format!("function{}", expr)));
|
||||
@ -1091,13 +1179,30 @@ impl<'a> Context<'a> {
|
||||
}
|
||||
self.expose_text_decoder();
|
||||
self.expose_uint8_memory();
|
||||
self.global(
|
||||
"
|
||||
function getStringFromWasm(ptr, len) {
|
||||
return cachedDecoder.decode(getUint8Memory().subarray(ptr, ptr + len));
|
||||
}
|
||||
",
|
||||
);
|
||||
|
||||
// Typically we try to give a raw view of memory out to `TextDecoder` to
|
||||
// avoid copying too much data. If, however, a `SharedArrayBuffer` is
|
||||
// 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) {
|
||||
@ -1284,18 +1389,20 @@ impl<'a> Context<'a> {
|
||||
if !self.exposed_globals.insert(name) {
|
||||
return;
|
||||
}
|
||||
let mem = self.memory();
|
||||
self.global(&format!(
|
||||
"
|
||||
let cache{name} = null;
|
||||
function {name}() {{
|
||||
if (cache{name} === null || cache{name}.buffer !== wasm.memory.buffer) {{
|
||||
cache{name} = new {js}(wasm.memory.buffer);
|
||||
if (cache{name} === null || cache{name}.buffer !== {mem}.buffer) {{
|
||||
cache{name} = new {js}({mem}.buffer);
|
||||
}}
|
||||
return cache{name};
|
||||
}}
|
||||
",
|
||||
name = name,
|
||||
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> {
|
||||
let module = mem::replace(self.module, Module::default());
|
||||
let module = module.parse_names().unwrap_or_else(|p| p.1);
|
||||
@ -1608,9 +1727,9 @@ impl<'a> Context<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn describe(&self, name: &str) -> Option<Descriptor> {
|
||||
fn describe(&mut self, name: &str) -> Option<Descriptor> {
|
||||
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) {
|
||||
@ -1628,6 +1747,29 @@ impl<'a> Context<'a> {
|
||||
fn use_node_require(&self) -> bool {
|
||||
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> {
|
||||
@ -1772,6 +1914,12 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
info: &shared::Import,
|
||||
import: &shared::ImportStatic,
|
||||
) -> 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
|
||||
let obj = self.import_name(info, &import.name)?;
|
||||
self.cx.expose_add_heap_object();
|
||||
@ -1799,132 +1947,39 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
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) {
|
||||
None => return Ok(()),
|
||||
Some(d) => d,
|
||||
};
|
||||
|
||||
let target = match &import.method {
|
||||
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" };
|
||||
let target = self.generated_import_target(info, import, &descriptor)?;
|
||||
|
||||
match 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 *is_static {
|
||||
("", format!(".bind({})", class))
|
||||
} else {
|
||||
(".prototype", "".into())
|
||||
};
|
||||
let js = Rust2Js::new(self.cx)
|
||||
.catch(import.catch)
|
||||
.variadic(import.variadic)
|
||||
.process(descriptor.unwrap_function())?
|
||||
.finish(&target);
|
||||
self.cx.export(&import.shim, &js, None);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
match 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
|
||||
));
|
||||
format!(
|
||||
"{}_target{}",
|
||||
import.shim,
|
||||
if *is_static { "" } else { ".call" }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn generated_import_target(
|
||||
&mut self,
|
||||
info: &shared::Import,
|
||||
import: &shared::ImportFunction,
|
||||
descriptor: &Descriptor,
|
||||
) -> Result<String, Error> {
|
||||
let method_data = match &import.method {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
let name = self.import_name(info, &import.function.name)?;
|
||||
if name.contains(".") {
|
||||
return Ok(if name.contains(".") {
|
||||
self.cx.global(&format!(
|
||||
"
|
||||
const {}_target = {};
|
||||
@ -1934,17 +1989,146 @@ impl<'a, 'b> SubContext<'a, 'b> {
|
||||
format!("{}_target", import.shim)
|
||||
} else {
|
||||
name
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let js = Rust2Js::new(self.cx)
|
||||
.catch(import.catch)
|
||||
.variadic(import.variadic)
|
||||
.process(descriptor.unwrap_function())?
|
||||
.finish(&target);
|
||||
self.cx.export(&import.shim, &js, None);
|
||||
Ok(())
|
||||
let class = match &method_data.class {
|
||||
Some(class) => self.import_name(info, class)?,
|
||||
None => {
|
||||
let op = match &method_data.kind {
|
||||
shared::MethodKind::Operation(op) => op,
|
||||
shared::MethodKind::Constructor => {
|
||||
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(
|
||||
|
@ -4,13 +4,13 @@ extern crate parity_wasm;
|
||||
extern crate wasm_bindgen_shared as shared;
|
||||
extern crate serde_json;
|
||||
extern crate wasm_gc;
|
||||
extern crate wasmi;
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
extern crate wasm_bindgen_wasm_interpreter as wasm_interpreter;
|
||||
|
||||
use std::any::Any;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::mem;
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -33,6 +33,9 @@ pub struct Bindgen {
|
||||
typescript: bool,
|
||||
demangle: 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 {
|
||||
@ -55,6 +58,7 @@ impl Bindgen {
|
||||
typescript: false,
|
||||
demangle: true,
|
||||
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
|
||||
// execute a shim function which informs us about its type so we can
|
||||
// then generate the appropriate bindings.
|
||||
//
|
||||
// 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 mut instance = wasm_interpreter::Interpreter::new(&module);
|
||||
|
||||
let (js, ts) = {
|
||||
let mut cx = js::Context {
|
||||
@ -201,20 +199,10 @@ impl Bindgen {
|
||||
config: &self,
|
||||
module: &mut module,
|
||||
function_table_needed: false,
|
||||
run_descriptor: &|name| {
|
||||
let mut v = MyExternals(Vec::new());
|
||||
match instance.invoke_export(name, &[], &mut v) {
|
||||
Ok(None) => Some(v.0),
|
||||
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),
|
||||
}
|
||||
},
|
||||
interpreter: &mut instance,
|
||||
memory_init: None,
|
||||
imported_functions: Default::default(),
|
||||
imported_statics: Default::default(),
|
||||
};
|
||||
for program in programs.iter() {
|
||||
js::SubContext {
|
||||
@ -336,7 +324,6 @@ fn extract_programs(module: &mut Module) -> Result<Vec<shared::Program>, Error>
|
||||
to_remove.push(i);
|
||||
|
||||
let mut payload = custom.payload();
|
||||
let mut added_programs = Vec::new();
|
||||
while payload.len() > 0 {
|
||||
let len = ((payload[0] as usize) << 0)
|
||||
| ((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);
|
||||
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) {
|
||||
Ok(f) => f,
|
||||
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)
|
||||
}
|
||||
|
||||
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 {
|
||||
let mut indent: u32 = 0;
|
||||
let mut dst = String::new();
|
||||
|
@ -150,19 +150,6 @@ impl Output {
|
||||
if let Some(i) = self.module.import_section() {
|
||||
let mut set = HashSet::new();
|
||||
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()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-cli"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli"
|
||||
@ -18,13 +18,13 @@ docopt = "1.0"
|
||||
env_logger = "0.5"
|
||||
failure = "0.1.2"
|
||||
log = "0.4"
|
||||
parity-wasm = "0.31"
|
||||
parity-wasm = "0.32"
|
||||
rouille = { version = "2.1.0", default-features = false }
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
serde_json = "1.0"
|
||||
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.17" }
|
||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.17" }
|
||||
wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.19" }
|
||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.19" }
|
||||
openssl = { version = '0.10.11', optional = true }
|
||||
|
||||
[features]
|
||||
|
@ -7,12 +7,12 @@ license = "MIT/Apache-2.0"
|
||||
name = "wasm-bindgen-futures"
|
||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/futures"
|
||||
readme = "./README.md"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1.20"
|
||||
js-sys = { path = "../js-sys", version = '0.2.1' }
|
||||
wasm-bindgen = { path = "../..", version = '0.2.17' }
|
||||
js-sys = { path = "../js-sys", version = '0.2.4' }
|
||||
wasm-bindgen = { path = "../..", version = '0.2.19' }
|
||||
|
||||
[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`.
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! #![feature(use_extern_macros)]
|
||||
//!
|
||||
//! extern crate futures;
|
||||
//! extern crate js_sys;
|
||||
//! extern crate wasm_bindgen;
|
||||
@ -104,7 +102,6 @@
|
||||
//! ```
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate wasm_bindgen;
|
||||
|
@ -1,4 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
extern crate futures;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "js-sys"
|
||||
version = "0.2.2"
|
||||
version = "0.2.4"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
readme = "./README.md"
|
||||
categories = ["wasm"]
|
||||
@ -18,7 +18,9 @@ test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../..", version = "0.2.17" }
|
||||
wasm-bindgen = { path = "../..", version = "0.2.19" }
|
||||
|
||||
[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")]
|
||||
|
||||
extern crate wasm_bindgen_test;
|
||||
|
@ -306,4 +306,5 @@ fn array_inheritance() {
|
||||
let array = Array::new();
|
||||
assert!(array.is_instance_of::<Array>());
|
||||
assert!(array.is_instance_of::<Object>());
|
||||
let _: &Object = array.as_ref();
|
||||
}
|
||||
|
@ -41,4 +41,5 @@ fn arraybuffer_inheritance() {
|
||||
let buf = ArrayBuffer::new(4);
|
||||
assert!(buf.is_instance_of::<ArrayBuffer>());
|
||||
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));
|
||||
assert!(b.is_instance_of::<Boolean>());
|
||||
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_test::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use js_sys::*;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test() {
|
||||
@ -36,7 +36,9 @@ fn test() {
|
||||
v.set_int8(0, 42);
|
||||
|
||||
// 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]
|
||||
@ -50,4 +52,5 @@ fn dataview_inheritance() {
|
||||
|
||||
assert!(v.is_instance_of::<DataView>());
|
||||
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());
|
||||
assert!(date.is_instance_of::<Date>());
|
||||
assert!(date.is_instance_of::<Object>());
|
||||
let _: &Object = date.as_ref();
|
||||
}
|
||||
|
@ -42,4 +42,5 @@ fn error_inheritance() {
|
||||
let error = Error::new("test");
|
||||
assert!(error.is_instance_of::<Error>());
|
||||
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::<Error>());
|
||||
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() {
|
||||
assert!(MAX.is_instance_of::<Function>());
|
||||
assert!(MAX.is_instance_of::<Object>());
|
||||
let _: &Object = MAX.as_ref();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_test::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use js_sys::*;
|
||||
|
||||
#[wasm_bindgen(module = "tests/wasm/Generator.js")]
|
||||
@ -56,3 +57,10 @@ fn throw() {
|
||||
assert!(next.value().is_undefined());
|
||||
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>());
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn date_time_format() {
|
||||
let locales = Array::of1(&JsValue::from("en-US"));
|
||||
@ -52,6 +63,17 @@ fn date_time_format() {
|
||||
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]
|
||||
fn number_format() {
|
||||
let locales = Array::of1(&JsValue::from("en-US"));
|
||||
@ -66,6 +88,17 @@ fn number_format() {
|
||||
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]
|
||||
fn plural_rules() {
|
||||
let locales = Array::of1(&JsValue::from("en-US"));
|
||||
@ -75,6 +108,17 @@ fn plural_rules() {
|
||||
assert!(r.resolved_options().is_instance_of::<Object>());
|
||||
assert_eq!(r.select(1_f64), "one");
|
||||
|
||||
let r = Intl::PluralRules::supported_locales_of(&locales, &opts);
|
||||
assert!(r.is_instance_of::<Array>());
|
||||
let a = Intl::PluralRules::supported_locales_of(&locales, &opts);
|
||||
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")]
|
||||
extern {
|
||||
fn new_string_object() -> JsValue;
|
||||
fn get_replacer_function() -> Function;
|
||||
}
|
||||
|
||||
#[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]), "½+¾=");
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn includes() {
|
||||
let str = JsString::from("Blue Whale");
|
||||
@ -135,6 +153,95 @@ fn last_index_of() {
|
||||
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]
|
||||
fn normalize() {
|
||||
let js = JsString::from("\u{1E9B}\u{0323}");
|
||||
@ -178,12 +285,106 @@ fn repeat() {
|
||||
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]
|
||||
fn slice() {
|
||||
let characters = JsString::from("acxn18");
|
||||
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]
|
||||
fn starts_with() {
|
||||
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();
|
||||
assert!(map.is_instance_of::<Map>());
|
||||
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));
|
||||
assert!(n.is_instance_of::<Number>());
|
||||
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::<Error>());
|
||||
assert!(error.is_instance_of::<Object>());
|
||||
let _: &Error = error.as_ref();
|
||||
let _: &Object = error.as_ref();
|
||||
|
||||
let base: &Error = error.as_ref();
|
||||
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::<Error>());
|
||||
assert!(error.is_instance_of::<Object>());
|
||||
let _: &Error = error.as_ref();
|
||||
let _: &Object = error.as_ref();
|
||||
|
||||
let base: &Error = error.as_ref();
|
||||
assert_eq!(JsValue::from(base.message()), "bad reference, fool");
|
||||
|
@ -7,6 +7,7 @@ fn regexp_inheritance() {
|
||||
let re = RegExp::new(".", "");
|
||||
assert!(re.is_instance_of::<RegExp>());
|
||||
assert!(re.is_instance_of::<Object>());
|
||||
let _: &Object = re.as_ref();
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
|
@ -87,4 +87,5 @@ fn set_inheritance() {
|
||||
let set = Set::new(&JsValue::undefined());
|
||||
assert!(set.is_instance_of::<Set>());
|
||||
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::<Error>());
|
||||
assert!(error.is_instance_of::<Object>());
|
||||
let _: &Error = error.as_ref();
|
||||
let _: &Object = error.as_ref();
|
||||
|
||||
let base: &Error = error.as_ref();
|
||||
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::<Error>());
|
||||
assert!(error.is_instance_of::<Object>());
|
||||
let _: &Error = error.as_ref();
|
||||
let _: &Object = error.as_ref();
|
||||
|
||||
let base: &Error = error.as_ref();
|
||||
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::<Error>());
|
||||
assert!(error.is_instance_of::<Object>());
|
||||
let _: &Error = error.as_ref();
|
||||
let _: &Object = error.as_ref();
|
||||
|
||||
let base: &Error = error.as_ref();
|
||||
assert_eq!(JsValue::from(base.message()), "msg");
|
||||
|
@ -57,4 +57,5 @@ fn weakmap_inheritance() {
|
||||
let map = WeakMap::new();
|
||||
assert!(map.is_instance_of::<WeakMap>());
|
||||
assert!(map.is_instance_of::<Object>());
|
||||
let _: &Object = map.as_ref();
|
||||
}
|
||||
|
@ -47,4 +47,5 @@ fn weakset_inheritance() {
|
||||
let set = WeakSet::new();
|
||||
assert!(set.is_instance_of::<WeakSet>());
|
||||
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 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]
|
||||
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")]
|
||||
#![feature(use_extern_macros)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate js_sys;
|
||||
extern crate wasm_bindgen;
|
||||
extern crate wasm_bindgen_futures;
|
||||
extern crate wasm_bindgen_test;
|
||||
|
||||
pub mod global_fns;
|
||||
@ -25,6 +26,7 @@ pub mod MapIterator;
|
||||
pub mod Math;
|
||||
pub mod Number;
|
||||
pub mod Object;
|
||||
pub mod Promise;
|
||||
pub mod Proxy;
|
||||
pub mod RangeError;
|
||||
pub mod ReferenceError;
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
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]
|
||||
spans = ["proc-macro2/nightly", "wasm-bindgen-backend/spans"]
|
||||
spans = ["wasm-bindgen-backend/spans"]
|
||||
extra-traits = ["syn/extra-traits"]
|
||||
|
||||
[dependencies]
|
||||
syn = { version = '0.14', features = ['full'] }
|
||||
quote = '0.6'
|
||||
proc-macro2 = "0.4.9"
|
||||
wasm-bindgen-backend = { path = "../backend", version = "=0.2.17" }
|
||||
wasm-bindgen-shared = { path = "../shared", version = "=0.2.17" }
|
||||
wasm-bindgen-backend = { path = "../backend", version = "=0.2.19" }
|
||||
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 }
|
||||
} else if opts.constructor() {
|
||||
let class = match wasm.ret {
|
||||
let class = match js_ret {
|
||||
Some(ref ty) => ty,
|
||||
_ => 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 ns = match kind {
|
||||
ast::ImportFunctionKind::ScopedMethod { .. } |
|
||||
ast::ImportFunctionKind::Normal => (0, "n"),
|
||||
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;
|
||||
|
||||
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() {
|
||||
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 shim = format!(
|
||||
"__wbg_static_accessor_{}_{}",
|
||||
js_name
|
||||
.chars()
|
||||
.filter(|c| c.is_ascii_alphanumeric())
|
||||
.collect::<String>(),
|
||||
self.ident
|
||||
self.ident,
|
||||
ShortHash((&js_name, module, &self.ident)),
|
||||
);
|
||||
Ok(ast::ImportKind::Static(ast::ImportStatic {
|
||||
ty: *self.ty,
|
||||
@ -991,7 +991,7 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
|
||||
let kind = match self {
|
||||
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?,
|
||||
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"),
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
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 = []
|
||||
|
||||
[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"
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,7 +1,7 @@
|
||||
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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,19 +1,19 @@
|
||||
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
|
||||
--> $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
|
||||
--> $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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,19 +1,19 @@
|
||||
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
|
||||
--> $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
|
||||
--> $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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,25 +1,25 @@
|
||||
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]
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,91 +1,91 @@
|
||||
error: it is currently not sound to use lifetimes in function signatures
|
||||
--> $DIR/invalid-imports.rs:11:16
|
||||
|
|
||||
11 | fn f() -> &'static u32;
|
||||
| ^^^^^^^
|
||||
--> $DIR/invalid-imports.rs:9:16
|
||||
|
|
||||
9 | fn f() -> &'static u32;
|
||||
| ^^^^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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
|
||||
|
|
||||
22 | fn f4(x: &::Bar);
|
||||
| ^^^^^
|
||||
22 | fn f4(x: &Bar<T>);
|
||||
| ^^^^^^
|
||||
|
||||
error: paths with type parameters are not supported yet
|
||||
--> $DIR/invalid-imports.rs:24:15
|
||||
|
|
||||
24 | fn f4(x: &Bar<T>);
|
||||
| ^^^^^^
|
||||
|
||||
error: paths with type parameters are not supported yet
|
||||
--> $DIR/invalid-imports.rs:26:15
|
||||
|
|
||||
26 | fn f4(x: &Fn(T));
|
||||
24 | fn f4(x: &Fn(T));
|
||||
| ^^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
--> $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<...>
|
||||
--> $DIR/invalid-imports.rs:36:15
|
||||
|
|
||||
36 | fn f() -> u32;
|
||||
| ^^^
|
||||
|
||||
error: must be Result<...>
|
||||
--> $DIR/invalid-imports.rs:38:15
|
||||
|
|
||||
38 | fn f() -> &u32;
|
||||
36 | fn f() -> &u32;
|
||||
| ^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,67 +1,67 @@
|
||||
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
|
||||
--> $DIR/invalid-items.rs:11:5
|
||||
|
|
||||
11 | pub unsafe fn foo1() {}
|
||||
| ^^^^^^
|
||||
--> $DIR/invalid-items.rs:9:5
|
||||
|
|
||||
9 | pub unsafe fn foo1() {}
|
||||
| ^^^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $DIR/invalid-items.rs:33:12
|
||||
|
|
||||
33 | pub fn foo5<'a>() {}
|
||||
| ^^^^
|
||||
|
||||
error: can't #[wasm_bindgen] functions with lifetime or type parameters
|
||||
--> $DIR/invalid-items.rs:35:12
|
||||
|
|
||||
35 | pub fn foo6<'a, T>() {}
|
||||
33 | pub fn foo6<'a, T>() {}
|
||||
| ^^^^^^^
|
||||
|
||||
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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,61 +1,61 @@
|
||||
error: #[wasm_bindgen] default impls are not supported
|
||||
--> $DIR/invalid-methods.rs:11:1
|
||||
|
|
||||
11 | default impl A {
|
||||
| ^^^^^^^
|
||||
--> $DIR/invalid-methods.rs:9:1
|
||||
|
|
||||
9 | default impl A {
|
||||
| ^^^^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
--> $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
|
||||
--> $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]
|
||||
--> $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]
|
||||
--> $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
|
||||
--> $DIR/invalid-methods.rs:36:5
|
||||
--> $DIR/invalid-methods.rs:34:5
|
||||
|
|
||||
36 | x!();
|
||||
34 | x!();
|
||||
| ^^^^^
|
||||
|
||||
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
|
||||
--> $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
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen;
|
||||
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -1,7 +1,7 @@
|
||||
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
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared"
|
||||
|
@ -3,7 +3,9 @@
|
||||
#[macro_use]
|
||||
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)]
|
||||
pub struct ProgramOnlySchema {
|
||||
@ -49,7 +51,7 @@ pub struct ImportFunction {
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct MethodData {
|
||||
pub class: String,
|
||||
pub class: Option<String>,
|
||||
pub kind: MethodKind,
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-test-macro"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
description = "Internal testing macro for wasm-bindgen"
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/rustwasm/wasm-bindgen"
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = { version = "0.4", features = ['nightly'] }
|
||||
proc-macro2 = "0.4"
|
||||
quote = "0.6"
|
||||
|
||||
[lib]
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wasm-bindgen-test"
|
||||
version = "0.2.17"
|
||||
version = "0.2.19"
|
||||
authors = ["The wasm-bindgen Developers"]
|
||||
description = "Internal testing crate for wasm-bindgen"
|
||||
license = "MIT/Apache-2.0"
|
||||
@ -9,11 +9,11 @@ repository = "https://github.com/rustwasm/wasm-bindgen"
|
||||
[dependencies]
|
||||
console_error_panic_hook = '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"
|
||||
wasm-bindgen = { path = '../..', version = '0.2.17' }
|
||||
wasm-bindgen-futures = { path = '../futures', version = '0.2.17' }
|
||||
wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.17' }
|
||||
wasm-bindgen = { path = '../..', version = '0.2.19' }
|
||||
wasm-bindgen-futures = { path = '../futures', version = '0.2.19' }
|
||||
wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.19' }
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
|
@ -38,8 +38,6 @@ ton of documentation just yet, but a taste of how it works is:
|
||||
|
||||
```rust
|
||||
// in tests/wasm.rs
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate wasm_bindgen_test;
|
||||
|
||||
use wasm_bindgen_test::*;
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate futures;
|
||||
extern crate js_sys;
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate sample;
|
||||
extern crate wasm_bindgen;
|
||||
|
@ -1,5 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate futures;
|
||||
extern crate sample;
|
||||
extern crate wasm_bindgen;
|
||||
|
@ -2,7 +2,6 @@
|
||||
//!
|
||||
//! More documentation can be found in the README for this crate!
|
||||
|
||||
#![feature(use_extern_macros)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
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"
|
||||
|
||||
[dependencies]
|
||||
wasm-bindgen = { path = "../..", version = "0.2.17" }
|
||||
js-sys = { path = '../js-sys', version = '0.2.1' }
|
||||
wasm-bindgen = { path = "../..", version = "0.2.19" }
|
||||
js-sys = { path = '../js-sys', version = '0.2.4' }
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
|
||||
futures = "0.1"
|
||||
js-sys = { path = '../js-sys', version = '0.2.1' }
|
||||
wasm-bindgen-test = { path = '../test', version = '0.2.17' }
|
||||
wasm-bindgen-futures = { path = '../futures', version = '0.2.17' }
|
||||
wasm-bindgen-test = { path = '../test', version = '0.2.19' }
|
||||
wasm-bindgen-futures = { path = '../futures', version = '0.2.19' }
|
||||
|
@ -3,6 +3,6 @@ use web_sys::console;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_console() {
|
||||
console::time_using_label("test label");
|
||||
console::time_end_using_label("test label");
|
||||
console::time_with_label("test label");
|
||||
console::time_end_with_label("test label");
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use web_sys::{DomPoint, DomPointReadOnly};
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
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);
|
||||
x.set_x(1.5);
|
||||
assert_eq!(x.x(), 1.5);
|
||||
@ -24,7 +24,7 @@ fn dom_point() {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
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));
|
||||
assert_eq!(x.x(), 1.0);
|
||||
assert_eq!(x.y(), 2.0);
|
||||
|
@ -1,4 +1,3 @@
|
||||
#![feature(use_extern_macros)]
|
||||
#![cfg(target_arch = "wasm32")]
|
||||
|
||||
extern crate futures;
|
||||
|
@ -3,7 +3,7 @@ use web_sys::HtmlOptionElement;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
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_value",
|
||||
false,
|
||||
|
@ -99,7 +99,7 @@ fn test_table_element() {
|
||||
);
|
||||
|
||||
table
|
||||
.insert_row_using_index(0)
|
||||
.insert_row_with_index(0)
|
||||
.expect("Failed to insert row at index 0");
|
||||
assert!(
|
||||
table.rows().length() == 1,
|
||||
|
@ -43,25 +43,25 @@ interface mixin WindowOrWorkerGlobalScope {
|
||||
};
|
||||
|
||||
// https://fetch.spec.whatwg.org/#fetch-method
|
||||
partial interface WindowOrWorkerGlobalScope {
|
||||
partial interface mixin WindowOrWorkerGlobalScope {
|
||||
[NewObject, NeedsCallerType]
|
||||
Promise<Response> fetch(RequestInfo input, optional RequestInit init);
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
|
||||
partial interface WindowOrWorkerGlobalScope {
|
||||
partial interface mixin WindowOrWorkerGlobalScope {
|
||||
readonly attribute boolean isSecureContext;
|
||||
};
|
||||
|
||||
// http://w3c.github.io/IndexedDB/#factory-interface
|
||||
partial interface WindowOrWorkerGlobalScope {
|
||||
partial interface mixin WindowOrWorkerGlobalScope {
|
||||
// readonly attribute IDBFactory indexedDB;
|
||||
[Throws]
|
||||
readonly attribute IDBFactory? indexedDB;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/ServiceWorker/#self-caches
|
||||
partial interface WindowOrWorkerGlobalScope {
|
||||
partial interface mixin WindowOrWorkerGlobalScope {
|
||||
[Throws, Func="mozilla::dom::DOMPrefs::DOMCachesEnabled", SameObject]
|
||||
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.i32(&[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.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 wasm_bindgen;
|
||||
extern crate wasm_bindgen_test;
|
||||
@ -12,3 +10,4 @@ pub mod namespace;
|
||||
pub mod simple;
|
||||
pub mod throws;
|
||||
pub mod dictionary;
|
||||
pub mod global;
|
||||
|
@ -87,11 +87,7 @@ global.Unforgeable = class Unforgeable {
|
||||
}
|
||||
};
|
||||
|
||||
global.GlobalMethod = class GlobalMethod {
|
||||
constructor() {
|
||||
this.m = () => 123;
|
||||
}
|
||||
};
|
||||
global.m = () => 123;
|
||||
|
||||
global.Indexing = function () {
|
||||
return new Proxy({}, {
|
||||
|
@ -50,7 +50,7 @@ fn static_property() {
|
||||
}
|
||||
|
||||
#[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();
|
||||
assert!(f.ok_method());
|
||||
}
|
||||
@ -64,8 +64,7 @@ fn nullable_method() {
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn global_method() {
|
||||
let f = GlobalMethod::new().unwrap();
|
||||
assert_eq!(f.m(), 123);
|
||||
assert_eq!(GlobalMethod::m(), 123);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
@ -81,14 +80,14 @@ fn indexing() {
|
||||
#[wasm_bindgen_test]
|
||||
fn optional_and_union_arguments() {
|
||||
let f = OptionalAndUnionArguments::new().unwrap();
|
||||
assert_eq!(f.m_using_a("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_using_dom_str_and_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_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_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_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_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("abc"), "string, abc, boolean, true, number, 123, number, 456");
|
||||
assert_eq!(f.m_with_b("abc", false), "string, abc, boolean, false, number, 123, 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_with_bool_and_str("abc", false, "5"), "string, abc, boolean, false, string, 5, number, 456");
|
||||
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_with_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_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_bool("abc", false, "5", Some(true)), "string, abc, boolean, false, string, 5, boolean, true");
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
|
@ -19,5 +19,5 @@ log = "0.4.1"
|
||||
proc-macro2 = "0.4.8"
|
||||
quote = '0.6'
|
||||
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"
|
||||
|
@ -348,13 +348,13 @@ impl<'a> IdlType<'a> {
|
||||
IdlType::UnsignedLong => dst.push_str("u32"),
|
||||
IdlType::LongLong => dst.push_str("i64"),
|
||||
IdlType::UnsignedLongLong => dst.push_str("u64"),
|
||||
IdlType::Float => dst.push_str("f32"),
|
||||
IdlType::UnrestrictedFloat => dst.push_str("unrestricted_f32"),
|
||||
IdlType::Double => dst.push_str("f64"),
|
||||
IdlType::UnrestrictedDouble => dst.push_str("unrestricted_f64"),
|
||||
IdlType::DomString => dst.push_str("dom_str"),
|
||||
IdlType::ByteString => dst.push_str("byte_str"),
|
||||
IdlType::UsvString => dst.push_str("usv_str"),
|
||||
IdlType::Float |
|
||||
IdlType::UnrestrictedFloat => dst.push_str("f32"),
|
||||
IdlType::Double |
|
||||
IdlType::UnrestrictedDouble => dst.push_str("f64"),
|
||||
IdlType::DomString |
|
||||
IdlType::ByteString |
|
||||
IdlType::UsvString => dst.push_str("str"),
|
||||
IdlType::Object => dst.push_str("object"),
|
||||
IdlType::Symbol => dst.push_str("symbol"),
|
||||
IdlType::Error => dst.push_str("error"),
|
||||
@ -459,7 +459,7 @@ impl<'a> IdlType<'a> {
|
||||
IdlType::DataView => None,
|
||||
IdlType::Int8Array => Some(array("i8", 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::Uint16Array => Some(array("u16", pos)),
|
||||
IdlType::Int32Array => Some(array("i32", pos)),
|
||||
|
@ -591,6 +591,11 @@ fn member_attribute<'src>(
|
||||
|
||||
let is_structural = util::is_structural(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(
|
||||
identifier,
|
||||
@ -599,6 +604,7 @@ fn member_attribute<'src>(
|
||||
is_static,
|
||||
is_structural,
|
||||
throws,
|
||||
global,
|
||||
) {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
@ -611,6 +617,7 @@ fn member_attribute<'src>(
|
||||
is_static,
|
||||
is_structural,
|
||||
throws,
|
||||
global,
|
||||
) {
|
||||
program.imports.push(wrap_import_function(import_function));
|
||||
}
|
||||
@ -712,6 +719,12 @@ fn member_operation<'src>(
|
||||
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 {
|
||||
let methods = first_pass
|
||||
.create_basic_method(
|
||||
@ -724,15 +737,10 @@ fn member_operation<'src>(
|
||||
OperationId::IndexingGetter |
|
||||
OperationId::IndexingSetter |
|
||||
OperationId::IndexingDeleter => true,
|
||||
_ => {
|
||||
first_pass
|
||||
.interfaces
|
||||
.get(self_name)
|
||||
.map(|interface_data| interface_data.global)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
util::throws(attrs),
|
||||
global,
|
||||
);
|
||||
|
||||
for method in methods {
|
||||
|
@ -273,9 +273,13 @@ impl<'src> FirstPassRecord<'src> {
|
||||
let rust_name = if possibilities.len() > 1 {
|
||||
let mut rust_name = rust_name.clone();
|
||||
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 {
|
||||
rust_name.push_str("_using_");
|
||||
rust_name.push_str("_with_");
|
||||
first = false;
|
||||
} else {
|
||||
rust_name.push_str("_and_");
|
||||
@ -293,6 +297,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
let rust_name = rust_ident(&rust_name);
|
||||
let shim = {
|
||||
let ns = match kind {
|
||||
backend::ast::ImportFunctionKind::ScopedMethod { .. } |
|
||||
backend::ast::ImportFunctionKind::Normal => "",
|
||||
backend::ast::ImportFunctionKind::Method { ref class, .. } => class,
|
||||
};
|
||||
@ -386,6 +391,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
is_static: bool,
|
||||
structural: bool,
|
||||
catch: bool,
|
||||
global: bool,
|
||||
) -> Vec<backend::ast::ImportFunction> {
|
||||
let (overloaded, same_argument_names) = self.get_operation_overloading(
|
||||
arguments,
|
||||
@ -407,20 +413,26 @@ impl<'src> FirstPassRecord<'src> {
|
||||
first_pass::OperationId::IndexingSetter => "set",
|
||||
first_pass::OperationId::IndexingDeleter => "delete",
|
||||
};
|
||||
|
||||
let kind = backend::ast::ImportFunctionKind::Method {
|
||||
class: self_name.to_string(),
|
||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||
is_static,
|
||||
kind: match &operation_id {
|
||||
first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
||||
first_pass::OperationId::Operation(_) => backend::ast::OperationKind::Regular,
|
||||
first_pass::OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
|
||||
first_pass::OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
|
||||
first_pass::OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
|
||||
},
|
||||
}),
|
||||
let operation_kind = match &operation_id {
|
||||
first_pass::OperationId::Constructor => panic!("constructors are unsupported"),
|
||||
first_pass::OperationId::Operation(_) => backend::ast::OperationKind::Regular,
|
||||
first_pass::OperationId::IndexingGetter => backend::ast::OperationKind::IndexingGetter,
|
||||
first_pass::OperationId::IndexingSetter => backend::ast::OperationKind::IndexingSetter,
|
||||
first_pass::OperationId::IndexingDeleter => backend::ast::OperationKind::IndexingDeleter,
|
||||
};
|
||||
let operation = backend::ast::Operation { is_static, kind: operation_kind };
|
||||
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
||||
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 ret = match return_type.to_idl_type(self) {
|
||||
@ -588,19 +600,29 @@ impl<'src> FirstPassRecord<'src> {
|
||||
is_static: bool,
|
||||
is_structural: bool,
|
||||
catch: bool,
|
||||
global: bool,
|
||||
) -> Vec<backend::ast::ImportFunction> {
|
||||
let ret = match ty.to_idl_type(self) {
|
||||
None => return Vec::new(),
|
||||
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 {
|
||||
class: self_name.to_string(),
|
||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||
is_static,
|
||||
kind: backend::ast::OperationKind::Getter(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 `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name))));
|
||||
|
||||
@ -611,19 +633,30 @@ impl<'src> FirstPassRecord<'src> {
|
||||
pub fn create_setter(
|
||||
&self,
|
||||
name: &str,
|
||||
ty: weedle::types::Type,
|
||||
field_ty: weedle::types::Type,
|
||||
self_name: &str,
|
||||
is_static: bool,
|
||||
is_structural: bool,
|
||||
catch: bool,
|
||||
global: bool,
|
||||
) -> Vec<backend::ast::ImportFunction> {
|
||||
let kind = backend::ast::ImportFunctionKind::Method {
|
||||
class: self_name.to_string(),
|
||||
ty: ident_ty(rust_ident(camel_case_ident(&self_name).as_str())),
|
||||
kind: backend::ast::MethodKind::Operation(backend::ast::Operation {
|
||||
is_static,
|
||||
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
||||
}),
|
||||
let operation = backend::ast::Operation {
|
||||
is_static,
|
||||
kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))),
|
||||
};
|
||||
let ty = ident_ty(rust_ident(camel_case_ident(&self_name).as_str()));
|
||||
|
||||
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))));
|
||||
|
||||
@ -633,7 +666,7 @@ impl<'src> FirstPassRecord<'src> {
|
||||
false,
|
||||
&[(
|
||||
name,
|
||||
match ty.to_idl_type(self) {
|
||||
match field_ty.to_idl_type(self) {
|
||||
None => return Vec::new(),
|
||||
Some(idl_type) => idl_type,
|
||||
},
|
||||
|
@ -10,31 +10,33 @@ when using `build.sh`!
|
||||
|
||||
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
|
||||
numbers.
|
||||
* `asm.js` - an example of using the `wasm2asm` tool from [binaryen] to convert
|
||||
the generated WebAssembly to normal JS
|
||||
* `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
|
||||
* `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
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user