diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index 0e74aa791..fada74bc8 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -21,4 +21,6 @@ doctest = false wasm-bindgen = { path = "../..", version = "0.2.17" } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] +futures = "0.1.20" wasm-bindgen-test = { path = '../test', version = '=0.2.17' } +wasm-bindgen-futures = { path = '../futures', version = '=0.2.17' } diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 58671c4f7..ff2362c42 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -2848,19 +2848,163 @@ extern "C" { pub fn delete(this: &WeakSet, value: &Object) -> bool; } -// WebAssembly -#[wasm_bindgen] -extern "C" { - #[derive(Clone, Debug)] - pub type WebAssembly; +#[allow(non_snake_case)] +pub mod WebAssembly { + use super::*; - /// The `WebAssembly.validate()` function validates a given typed - /// array of WebAssembly binary code, returning whether the bytes - /// form a valid wasm module (`true`) or not (`false`). - /// - /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/validate - #[wasm_bindgen(static_method_of = WebAssembly, catch)] - pub fn validate(bufferSource: &JsValue) -> Result; + // WebAssembly + #[wasm_bindgen] + extern "C" { + /// `The WebAssembly.compile()` function compiles a `WebAssembly.Module` + /// from WebAssembly binary code. This function is useful if it is + /// necessary to a compile a module before it can be instantiated + /// (otherwise, the `WebAssembly.instantiate()` function should be used). + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/compile + #[wasm_bindgen(js_namespace = WebAssembly)] + pub fn compile(buffer_source: &JsValue) -> Promise; + + /// The `WebAssembly.validate()` function validates a given typed + /// array of WebAssembly binary code, returning whether the bytes + /// form a valid wasm module (`true`) or not (`false`). + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/validate + #[wasm_bindgen(js_namespace = WebAssembly, catch)] + pub fn validate(buffer_source: &JsValue) -> Result; + } + + // WebAssembly.CompileError + #[wasm_bindgen] + extern "C" { + /// The `WebAssembly.CompileError()` constructor creates a new + /// WebAssembly `CompileError` object, which indicates an error during + /// WebAssembly decoding or validation. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError + #[wasm_bindgen(extends = Error, js_namespace = WebAssembly)] + #[derive(Clone, Debug)] + pub type CompileError; + + /// The `WebAssembly.CompileError()` constructor creates a new + /// WebAssembly `CompileError` object, which indicates an error during + /// WebAssembly decoding or validation. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError + #[wasm_bindgen(constructor, js_namespace = WebAssembly)] + pub fn new(message: &str) -> CompileError; + } + + // WebAssembly.LinkError + #[wasm_bindgen] + extern "C" { + /// The `WebAssembly.LinkError()` constructor creates a new WebAssembly + /// LinkError object, which indicates an error during module + /// instantiation (besides traps from the start function). + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError + #[wasm_bindgen(extends = Error, js_namespace = WebAssembly)] + #[derive(Clone, Debug)] + pub type LinkError; + + /// The `WebAssembly.LinkError()` constructor creates a new WebAssembly + /// LinkError object, which indicates an error during module + /// instantiation (besides traps from the start function). + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError + #[wasm_bindgen(constructor, js_namespace = WebAssembly)] + pub fn new(message: &str) -> LinkError; + } + + // WebAssembly.RuntimeError + #[wasm_bindgen] + extern "C" { + /// The `WebAssembly.RuntimeError()` constructor creates a new WebAssembly + /// `RuntimeError` object — the type that is thrown whenever WebAssembly + /// specifies a trap. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/RuntimeError + #[wasm_bindgen(extends = Error, js_namespace = WebAssembly)] + #[derive(Clone, Debug)] + pub type RuntimeError; + + /// The `WebAssembly.RuntimeError()` constructor creates a new WebAssembly + /// `RuntimeError` object — the type that is thrown whenever WebAssembly + /// specifies a trap. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/RuntimeError + #[wasm_bindgen(constructor, js_namespace = WebAssembly)] + pub fn new(message: &str) -> RuntimeError; + } + + // WebAssembly.Module + #[wasm_bindgen] + extern "C" { + /// A `WebAssembly.Module` object contains stateless WebAssembly code + /// that has already been compiled by the browser and can be + /// efficiently shared with Workers, and instantiated multiple times. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module + #[wasm_bindgen(js_namespace = WebAssembly, extends = Object)] + #[derive(Clone, Debug)] + pub type Module; + + /// A `WebAssembly.Module` object contains stateless WebAssembly code + /// that has already been compiled by the browser and can be + /// efficiently shared with Workers, and instantiated multiple times. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module + #[wasm_bindgen(constructor, js_namespace = WebAssembly, catch)] + pub fn new(buffer_source: &JsValue) -> Result; + + /// The `WebAssembly.customSections()` function returns a copy of the + /// contents of all custom sections in the given module with the given + /// string name. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/customSections + #[wasm_bindgen(static_method_of = Module, js_namespace = WebAssembly, js_name = customSections)] + pub fn custom_sections(module: &Module, sectionName: &str) -> Array; + + /// The `WebAssembly.exports()` function returns an array containing + /// descriptions of all the declared exports of the given `Module`. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/exports + #[wasm_bindgen(static_method_of = Module, js_namespace = WebAssembly)] + pub fn exports(module: &Module) -> Array; + + /// The `WebAssembly.imports()` function returns an array containing + /// descriptions of all the declared imports of the given `Module`. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module/imports + #[wasm_bindgen(static_method_of = Module, js_namespace = WebAssembly)] + pub fn imports(module: &Module) -> Array; + } + + // WebAssembly.Table + #[wasm_bindgen] + extern "C" { + /// The `WebAssembly.Table()` constructor creates a new `Table` object + /// of the given size and element type. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table + #[wasm_bindgen(js_namespace = WebAssembly, extends = Object)] + #[derive(Clone, Debug)] + pub type Table; + + /// The `WebAssembly.Table()` constructor creates a new `Table` object + /// of the given size and element type. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table + #[wasm_bindgen(constructor, js_namespace = WebAssembly, catch)] + pub fn new(table_descriptor: &Object) -> Result; + + /// The `length` prototype property of the `WebAssembly.Table` object + /// returns the length of the table, i.e. the number of elements in the + /// table. + /// + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/length + #[wasm_bindgen(method, getter, js_namespace = WebAssembly)] + pub fn length(this: &Table) -> u32; + } } // JSON diff --git a/crates/js-sys/tests/wasm/WebAssembly.js b/crates/js-sys/tests/wasm/WebAssembly.js new file mode 100644 index 000000000..51d0c343a --- /dev/null +++ b/crates/js-sys/tests/wasm/WebAssembly.js @@ -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, +}; diff --git a/crates/js-sys/tests/wasm/WebAssembly.rs b/crates/js-sys/tests/wasm/WebAssembly.rs index 14fc5307a..fe16378e6 100644 --- a/crates/js-sys/tests/wasm/WebAssembly.rs +++ b/crates/js-sys/tests/wasm/WebAssembly.rs @@ -1,9 +1,155 @@ -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 { + let p = WebAssembly::compile(&get_invalid_wasm()); + JsFuture::from(p) + .map(|_| unreachable!()) + .or_else(|e| { + assert!(e.is_instance_of::()); + Ok(()) + }) +} + +#[wasm_bindgen_test(async)] +fn compile_type_error() -> impl Future { + let p = WebAssembly::compile(&get_bad_type_wasm()); + JsFuture::from(p) + .map(|_| unreachable!()) + .or_else(|e| { + assert!(e.is_instance_of::()); + Ok(()) + }) +} + +#[wasm_bindgen_test(async)] +fn compile_valid() -> impl Future { + let p = WebAssembly::compile(&get_valid_wasm()); + JsFuture::from(p) + .map(|module| { + assert!(module.is_instance_of::()); + }) + .map_err(|_| unreachable!()) +} + +#[wasm_bindgen_test] +fn module_inheritance() { + let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap(); + assert!(module.is_instance_of::()); + assert!(module.is_instance_of::()); + + 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::()); + + let error = WebAssembly::Module::new(&get_bad_type_wasm()).err().unwrap(); + assert!(error.is_instance_of::()); +} + +#[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::()); + assert!(table.is_instance_of::()); + + 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::()); +} + +#[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::()); + assert!(error.is_instance_of::()); + + let _: &Error = error.as_ref(); +} + +#[wasm_bindgen_test] +fn link_error_inheritance() { + let error = WebAssembly::LinkError::new(""); + assert!(error.is_instance_of::()); + assert!(error.is_instance_of::()); + + let _: &Error = error.as_ref(); +} + +#[wasm_bindgen_test] +fn runtime_error_inheritance() { + let error = WebAssembly::RuntimeError::new(""); + assert!(error.is_instance_of::()); + assert!(error.is_instance_of::()); + + let _: &Error = error.as_ref(); } diff --git a/crates/js-sys/tests/wasm/main.rs b/crates/js-sys/tests/wasm/main.rs index 7cdcc54a3..285e2ae3c 100755 --- a/crates/js-sys/tests/wasm/main.rs +++ b/crates/js-sys/tests/wasm/main.rs @@ -1,8 +1,10 @@ #![cfg(target_arch = "wasm32")] #![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;