diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 89e728eed32..6f9bc275bcb 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -1203,6 +1203,7 @@ extern { #[wasm_bindgen] extern "C" { #[derive(Clone, Debug)] + #[wasm_bindgen(extends = Object)] pub type Math; /// The Math.abs() function returns the absolute value of a number, that is @@ -2127,6 +2128,7 @@ extern { #[wasm_bindgen] extern "C" { #[derive(Clone, Debug)] + #[wasm_bindgen(extends = Object)] pub type Reflect; /// The static `Reflect.apply()` method calls a target function with @@ -2864,6 +2866,29 @@ pub mod WebAssembly { #[wasm_bindgen(js_namespace = WebAssembly)] pub fn compile(buffer_source: &JsValue) -> Promise; + /// The `WebAssembly.instantiate()` function allows you to compile and + /// instantiate WebAssembly code. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate) + #[wasm_bindgen(js_namespace = WebAssembly, js_name = instantiate)] + pub fn instantiate_buffer(buffer: &[u8], imports: &Object) -> Promise; + + /// The `WebAssembly.instantiate()` function allows you to compile and + /// instantiate WebAssembly code. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate) + #[wasm_bindgen(js_namespace = WebAssembly, js_name = instantiate)] + pub fn instantiate_module(module: &Module, imports: &Object) -> Promise; + + /// The `WebAssembly.instantiateStreaming()` function compiles and + /// instantiates a WebAssembly module directly from a streamed + /// underlying source. This is the most efficient, optimized way to load + /// wasm code. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming) + #[wasm_bindgen(js_namespace = WebAssembly, js_name = instantiateStreaming)] + pub fn instantiate_streaming(response: &Promise, imports: &Object) -> 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`). @@ -2894,6 +2919,38 @@ pub mod WebAssembly { pub fn new(message: &str) -> CompileError; } + // WebAssembly.Instance + #[wasm_bindgen] + extern "C" { + /// A `WebAssembly.Instance` object is a stateful, executable instance + /// of a `WebAssembly.Module`. Instance objects contain all the exported + /// WebAssembly functions that allow calling into WebAssembly code from + /// JavaScript. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance) + #[wasm_bindgen(extends = Object, js_namespace = WebAssembly)] + #[derive(Clone, Debug)] + pub type Instance; + + /// The `WebAssembly.Instance()` constructor function can be called to + /// synchronously instantiate a given `WebAssembly.Module` + /// object. However, the primary way to get an `Instance` is through the + /// asynchronous `WebAssembly.instantiateStreaming()` function. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance) + #[wasm_bindgen(catch, constructor, js_namespace = WebAssembly)] + pub fn new(module: &Module, imports: &Object) -> Result; + + /// The `exports` readonly property of the `WebAssembly.Instance` object + /// prototype returns an object containing as its members all the + /// functions exported from the WebAssembly module instance, to allow + /// them to be accessed and used by JavaScript. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports) + #[wasm_bindgen(getter, method, js_namespace = WebAssembly)] + pub fn exports(this: &Instance) -> Object; + } + // WebAssembly.LinkError #[wasm_bindgen] extern "C" { @@ -3004,6 +3061,28 @@ pub mod WebAssembly { /// [MDN documentation](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; + + /// The `get()` prototype method of the `WebAssembly.Table()` object + /// retrieves a function reference stored at a given index. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get) + #[wasm_bindgen(method, catch, js_namespace = WebAssembly)] + pub fn get(this: &Table, index: u32) -> Result; + + /// The `grow()` prototype method of the `WebAssembly.Table` object + /// increases the size of the `Table` instance by a specified number of + /// elements. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/grow) + #[wasm_bindgen(method, catch, js_namespace = WebAssembly)] + pub fn grow(this: &Table, additional_capacity: u32) -> Result; + + /// The `set()` prototype method of the `WebAssembly.Table` object mutates a + /// reference stored at a given index to a different value. + /// + /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set) + #[wasm_bindgen(method, catch, js_namespace = WebAssembly)] + pub fn set(this: &Table, index: u32, function: &Function) -> Result<(), JsValue>; } // WebAssembly.Memory @@ -3048,8 +3127,12 @@ pub mod WebAssembly { // JSON #[wasm_bindgen] extern "C" { - + /// The `JSON` object contains methods for parsing [JavaScript Object + /// Notation (JSON)](https://json.org/) and converting values to JSON. It + /// can't be called or constructed, and aside from its two method + /// properties, it has no interesting functionality of its own. #[derive(Clone, Debug)] + #[wasm_bindgen(extends = Object)] pub type JSON; /// The `JSON.parse()` method parses a JSON string, constructing the diff --git a/crates/js-sys/tests/wasm/JSON.rs b/crates/js-sys/tests/wasm/JSON.rs index b1d9fd1841b..d38bae3bc59 100644 --- a/crates/js-sys/tests/wasm/JSON.rs +++ b/crates/js-sys/tests/wasm/JSON.rs @@ -1,4 +1,4 @@ -use wasm_bindgen::JsValue; +use wasm_bindgen::prelude::*; use wasm_bindgen_test::*; use wasm_bindgen::JsCast; use js_sys::*; @@ -82,3 +82,15 @@ fn stringify_error() { let err_msg: String = From::from(err.message()); assert!(err_msg.contains("rust really rocks")); } + +#[wasm_bindgen_test] +fn json_extends() { + #[wasm_bindgen] + extern { + #[wasm_bindgen(js_name = JSON)] + static json: JSON; + } + + assert!(json.is_instance_of::()); + let _: &Object = json.as_ref(); +} diff --git a/crates/js-sys/tests/wasm/Math.rs b/crates/js-sys/tests/wasm/Math.rs index a46ded34fd7..c6047fca6d7 100644 --- a/crates/js-sys/tests/wasm/Math.rs +++ b/crates/js-sys/tests/wasm/Math.rs @@ -1,9 +1,22 @@ use std::f64::consts::PI; use std::f64::{NEG_INFINITY, NAN}; +use wasm_bindgen::{JsCast, prelude::*}; use wasm_bindgen_test::*; use js_sys::*; +#[wasm_bindgen_test] +fn math_extends() { + #[wasm_bindgen] + extern { + #[wasm_bindgen(js_name = Math)] + static math: Math; + } + + assert!(math.is_instance_of::()); + let _: &Object = math.as_ref(); +} + macro_rules! assert_eq { ($a:expr, $b:expr) => ({ let (a, b) = (&$a, &$b); diff --git a/crates/js-sys/tests/wasm/Reflect.rs b/crates/js-sys/tests/wasm/Reflect.rs index 5f6f47f1779..da2c5217a7b 100644 --- a/crates/js-sys/tests/wasm/Reflect.rs +++ b/crates/js-sys/tests/wasm/Reflect.rs @@ -1,4 +1,4 @@ -use wasm_bindgen::prelude::*; +use wasm_bindgen::{JsCast, prelude::*}; use wasm_bindgen_test::*; use js_sys::*; @@ -180,3 +180,15 @@ fn set_prototype_of() { let obj = JsValue::from(obj); assert_eq!(JsValue::from(Reflect::get_prototype_of(&obj)), JsValue::null()); } + +#[wasm_bindgen_test] +fn reflect_extends() { + #[wasm_bindgen] + extern { + #[wasm_bindgen(js_name = Reflect)] + static reflect: Reflect; + } + + assert!(reflect.is_instance_of::()); + let _: &Object = reflect.as_ref(); +} diff --git a/crates/js-sys/tests/wasm/WebAssembly.js b/crates/js-sys/tests/wasm/WebAssembly.js index 51d0c343a71..694046853d4 100644 --- a/crates/js-sys/tests/wasm/WebAssembly.js +++ b/crates/js-sys/tests/wasm/WebAssembly.js @@ -21,8 +21,25 @@ function getInvalidTableObject() { return { element: "anyfunc", initial: 1, maximum: 0 } } +function getImports() { + return { + imports: { + imported_func: function () { + return 1; + } + } + }; +} + +// Polyfill `WebAssembly.instantiateStreaming` for node. +if (!global.WebAssembly.instantiateStreaming) { + global.WebAssembly.instantiateStreaming = + (response, imports) => response.then(buf => WebAssembly.instantiate(buf, imports)); +} + module.exports = { getInvalidTableObject, getTableObject, getWasmArray, + getImports, }; diff --git a/crates/js-sys/tests/wasm/WebAssembly.rs b/crates/js-sys/tests/wasm/WebAssembly.rs index 35207f968b3..65385ec5938 100644 --- a/crates/js-sys/tests/wasm/WebAssembly.rs +++ b/crates/js-sys/tests/wasm/WebAssembly.rs @@ -1,11 +1,11 @@ use futures::Future; use js_sys::*; -use wasm_bindgen::{JsCast, prelude::*}; +use wasm_bindgen::{prelude::*, JsCast}; use wasm_bindgen_futures::JsFuture; use wasm_bindgen_test::*; #[wasm_bindgen(module = "tests/wasm/WebAssembly.js")] -extern { +extern "C" { #[wasm_bindgen(js_name = getWasmArray)] fn get_wasm_array() -> Uint8Array; @@ -14,6 +14,9 @@ extern { #[wasm_bindgen(js_name = getInvalidTableObject)] fn get_invalid_table_object() -> Object; + + #[wasm_bindgen(js_name = getImports)] + fn get_imports() -> Object; } fn get_invalid_wasm() -> JsValue { @@ -38,23 +41,19 @@ fn validate() { #[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(()) - }) + 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(()) - }) + JsFuture::from(p).map(|_| unreachable!()).or_else(|e| { + assert!(e.is_instance_of::()); + Ok(()) + }) } #[wasm_bindgen_test(async)] @@ -63,8 +62,7 @@ fn compile_valid() -> impl Future { JsFuture::from(p) .map(|module| { assert!(module.is_instance_of::()); - }) - .map_err(|_| unreachable!()) + }).map_err(|_| unreachable!()) } #[wasm_bindgen_test] @@ -81,7 +79,9 @@ 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(); + let error = WebAssembly::Module::new(&get_bad_type_wasm()) + .err() + .unwrap(); assert!(error.is_instance_of::()); } @@ -117,7 +117,9 @@ fn table_inheritance() { #[wasm_bindgen_test] fn table_error() { - let error = WebAssembly::Table::new(&get_invalid_table_object()).err().unwrap(); + let error = WebAssembly::Table::new(&get_invalid_table_object()) + .err() + .unwrap(); assert!(error.is_instance_of::()); } @@ -125,6 +127,15 @@ fn table_error() { fn table() { let table = WebAssembly::Table::new(&get_table_object().into()).unwrap(); assert_eq!(table.length(), 1); + + assert!(table.get(0).is_ok()); + assert!(table.get(999).is_err()); + + table.grow(1).unwrap(); + assert_eq!(table.length(), 2); + + let f = table.get(0).unwrap(); + table.set(1, &f).unwrap(); } #[wasm_bindgen_test] @@ -154,6 +165,47 @@ fn runtime_error_inheritance() { let _: &Error = error.as_ref(); } +#[wasm_bindgen_test] +fn webassembly_instance() { + let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap(); + let imports = get_imports(); + let instance = WebAssembly::Instance::new(&module, &imports).unwrap(); + + // Inheritance chain is correct. + assert!(instance.is_instance_of::()); + assert!(instance.is_instance_of::()); + let _: &Object = instance.as_ref(); + + // Has expected exports. + let exports = instance.exports(); + assert!(Reflect::has(exports.as_ref(), &"exported_func".into())); +} + +#[wasm_bindgen_test(async)] +fn instantiate_module() -> impl Future { + let module = WebAssembly::Module::new(&get_valid_wasm()).unwrap(); + let imports = get_imports(); + let p = WebAssembly::instantiate_module(&module, &imports); + JsFuture::from(p) + .map(|inst| { + assert!(inst.is_instance_of::()); + }) +} + +#[wasm_bindgen_test(async)] +fn instantiate_streaming() -> impl Future { + let response = Promise::resolve(&get_valid_wasm()); + let imports = get_imports(); + let p = WebAssembly::instantiate_streaming(&response, &imports); + JsFuture::from(p) + .map(|obj| { + assert!( + Reflect::get(obj.as_ref(), &"instance".into()) + .is_instance_of::() + ); + }) +} + #[wasm_bindgen_test] fn memory_works() { let obj = Object::new(); @@ -166,7 +218,10 @@ fn memory_works() { assert_eq!(mem.grow(2), 2); assert_eq!(mem.grow(3), 4); assert_eq!( - mem.buffer().dyn_into::().unwrap().byte_length(), + mem.buffer() + .dyn_into::() + .unwrap() + .byte_length(), 7 * 64 * 1024, ); }