Skip to content

Lots more js-sys bindings #795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Sep 6, 2018
85 changes: 84 additions & 1 deletion crates/js-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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`).
Expand Down Expand Up @@ -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<Instance, JsValue>;

/// 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" {
Expand Down Expand Up @@ -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<Function, JsValue>;

/// 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<u32, JsValue>;

/// 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
Expand Down Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion crates/js-sys/tests/wasm/JSON.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use wasm_bindgen::JsValue;
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use wasm_bindgen::JsCast;
use js_sys::*;
Expand Down Expand Up @@ -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::<Object>());
let _: &Object = json.as_ref();
}
13 changes: 13 additions & 0 deletions crates/js-sys/tests/wasm/Math.rs
Original file line number Diff line number Diff line change
@@ -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::<Object>());
let _: &Object = math.as_ref();
}

macro_rules! assert_eq {
($a:expr, $b:expr) => ({
let (a, b) = (&$a, &$b);
Expand Down
14 changes: 13 additions & 1 deletion crates/js-sys/tests/wasm/Reflect.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use wasm_bindgen::prelude::*;
use wasm_bindgen::{JsCast, prelude::*};
use wasm_bindgen_test::*;
use js_sys::*;

Expand Down Expand Up @@ -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::<Object>());
let _: &Object = reflect.as_ref();
}
17 changes: 17 additions & 0 deletions crates/js-sys/tests/wasm/WebAssembly.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
93 changes: 74 additions & 19 deletions crates/js-sys/tests/wasm/WebAssembly.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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 {
Expand All @@ -38,23 +41,19 @@ fn validate() {
#[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(())
})
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(())
})
JsFuture::from(p).map(|_| unreachable!()).or_else(|e| {
assert!(e.is_instance_of::<TypeError>());
Ok(())
})
}

#[wasm_bindgen_test(async)]
Expand All @@ -63,8 +62,7 @@ fn compile_valid() -> impl Future<Item = (), Error = JsValue> {
JsFuture::from(p)
.map(|module| {
assert!(module.is_instance_of::<WebAssembly::Module>());
})
.map_err(|_| unreachable!())
}).map_err(|_| unreachable!())
}

#[wasm_bindgen_test]
Expand All @@ -81,7 +79,9 @@ 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();
let error = WebAssembly::Module::new(&get_bad_type_wasm())
.err()
.unwrap();
assert!(error.is_instance_of::<TypeError>());
}

Expand Down Expand Up @@ -117,14 +117,25 @@ 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::<RangeError>());
}

#[wasm_bindgen_test]
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]
Expand Down Expand Up @@ -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::<WebAssembly::Instance>());
assert!(instance.is_instance_of::<Object>());
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<Item = (), Error = JsValue> {
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::<WebAssembly::Instance>());
})
}

#[wasm_bindgen_test(async)]
fn instantiate_streaming() -> impl Future<Item = (), Error = JsValue> {
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::<WebAssembly::Instance>()
);
})
}

#[wasm_bindgen_test]
fn memory_works() {
let obj = Object::new();
Expand All @@ -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::<ArrayBuffer>().unwrap().byte_length(),
mem.buffer()
.dyn_into::<ArrayBuffer>()
.unwrap()
.byte_length(),
7 * 64 * 1024,
);
}