Merge branch 'master' into variadic_js_functions

This commit is contained in:
Richard Dodd 2018-08-31 10:08:53 +01:00
commit ce1cb84327
166 changed files with 3186 additions and 10757 deletions

View File

@ -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
View File

@ -7,3 +7,5 @@ package-lock.json
npm-shrinkwrap.json
yarn.lock
*.d.ts
/publish
/publish.exe

View File

@ -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

View File

@ -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.

View File

@ -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",
]

View File

@ -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
View File

@ -0,0 +1,2 @@
// Empty `build.rs` so that `[package] links = ...` works in `Cargo.toml`.
fn main() {}

View File

@ -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" }

View File

@ -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,
};

View File

@ -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);

View File

@ -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 => {}
}
}

View File

@ -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"

View File

@ -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
}

View File

@ -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(

View File

@ -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();

View File

@ -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;
}

View File

@ -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]

View File

@ -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' }

View File

@ -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;

View File

@ -1,4 +1,3 @@
#![feature(use_extern_macros)]
#![cfg(target_arch = "wasm32")]
extern crate futures;

View File

@ -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

View File

@ -1,4 +1,3 @@
#![feature(use_extern_macros)]
#![cfg(target_arch = "wasm32")]
extern crate wasm_bindgen_test;

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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>());
}

View File

@ -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();
}

View File

@ -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();
};
};

View File

@ -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.");

View File

@ -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();
}

View File

@ -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();
}

View 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();
}

View File

@ -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");

View File

@ -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");

View File

@ -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]

View File

@ -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();
}

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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();
}

View File

@ -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();
}

View 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,
};

View File

@ -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,
);
}

View File

@ -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;

View File

@ -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" }

View File

@ -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"),
};

View File

@ -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"

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

View File

@ -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

View File

@ -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"

View File

@ -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,
}

View File

@ -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]

View File

@ -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

View File

@ -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::*;

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
#[macro_use]
extern crate futures;
extern crate js_sys;

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate futures;
extern crate sample;
extern crate wasm_bindgen;

View File

@ -1,5 +1,3 @@
#![feature(use_extern_macros)]
extern crate futures;
extern crate sample;
extern crate wasm_bindgen;

View File

@ -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;

View 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"

View 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);
}
}

View 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]));
}

View File

@ -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' }

View File

@ -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");
}

View File

@ -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);

View File

@ -1,4 +1,3 @@
#![feature(use_extern_macros)]
#![cfg(target_arch = "wasm32")]
extern crate futures;

View File

@ -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,

View File

@ -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,

View File

@ -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;
};

View File

@ -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]);
}

View File

@ -0,0 +1,4 @@
global.global_no_args = () => 3;
global.global_with_args = (a, b) => a + b;
global.global_attribute = 'x';

View 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
View 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;
};

View File

@ -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;

View File

@ -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({}, {

View File

@ -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]

View File

@ -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"

View File

@ -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)),

View File

@ -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 {

View File

@ -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,
},

View File

@ -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