From 2f28b8b80e3f5daaaf9d11df661607541293c6c6 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Mon, 1 Apr 2019 13:08:08 +0100 Subject: [PATCH 01/23] Optimise encodeInto reallocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of doubling the size on each iteration, use precise upper limit (3 * JS length) if the string turned out not to be ASCII-only. This results in maximum of 1 reallocation instead of O(log N). Some dummy examples of what this would change: - 1000 of ASCII chars: no change, allocates 1000 bytes and bails out. - 1000 ASCII chars + 1 '😃': before allocated 1000 bytes and reallocated to 2000; now allocates 1000 bytes and reallocates to 1006. - 1000 of '😃' chars: before allocated 1000 bytes, reallocated to 2000, finally reallocated again to 4000; now allocates 1000 bytes and reallocates to 4000 right away. Related issue: #1313 --- crates/cli-support/src/js/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 4a9fabcd..fdbb2199 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1306,13 +1306,12 @@ impl<'a> Context<'a> { while (true) {{ const view = getUint8Memory().subarray(ptr + writeOffset, ptr + size); const {{ read, written }} = cachedTextEncoder.encodeInto(arg, view); - arg = arg.substring(read); - writeOffset += written; - if (arg.length === 0) {{ + if (read === arg.length) {{ break; }} - ptr = wasm.__wbindgen_realloc(ptr, size, size * 2); - size *= 2; + arg = arg.substring(read); + writeOffset += written; + ptr = wasm.__wbindgen_realloc(ptr, size, size += arg.length * 3); }} WASM_VECTOR_LEN = writeOffset; return ptr; From d48f4995e5fb4be68b0ee206e9b56f9b5e6aa572 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 1 Apr 2019 11:00:09 -0700 Subject: [PATCH 02/23] Support 1-reference argument closures This is work towards #1399, although it's just for one-argument closures where the first argument is a reference. No other closures with references in argument position are supported yet --- src/closure.rs | 151 +++++++++++++++++++++++++++++++++++++++- src/convert/closures.rs | 95 +++++++++++++++++++++++++ tests/wasm/closures.js | 6 ++ tests/wasm/closures.rs | 83 ++++++++++++++++++++++ 4 files changed, 332 insertions(+), 3 deletions(-) diff --git a/src/closure.rs b/src/closure.rs index 885b5975..5067c799 100644 --- a/src/closure.rs +++ b/src/closure.rs @@ -519,7 +519,7 @@ where /// This trait is not stable and it's not recommended to use this in bounds or /// implement yourself. #[doc(hidden)] -pub unsafe trait WasmClosure: 'static { +pub unsafe trait WasmClosure { fn describe(); } @@ -541,7 +541,7 @@ macro_rules! doit { ($( ($($var:ident)*) )*) => ($( - unsafe impl<$($var,)* R> WasmClosure for Fn($($var),*) -> R + unsafe impl<$($var,)* R> WasmClosure for Fn($($var),*) -> R + 'static where $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static, { @@ -587,7 +587,7 @@ macro_rules! doit { } } - unsafe impl<$($var,)* R> WasmClosure for FnMut($($var),*) -> R + unsafe impl<$($var,)* R> WasmClosure for FnMut($($var),*) -> R + 'static where $($var: FromWasmAbi + 'static,)* R: ReturnWasmAbi + 'static, { @@ -696,3 +696,148 @@ doit! { (A B C D E F) (A B C D E F G) } + +// Copy the above impls down here for where there's only one argument and it's a +// reference. We could add more impls for more kinds of references, but it +// becomes a combinatorial explosion quickly. Let's see how far we can get with +// just this one! Maybe someone else can figure out voodoo so we don't have to +// duplicate. + +unsafe impl WasmClosure for Fn(&A) -> R + where A: RefFromWasmAbi, + R: ReturnWasmAbi + 'static, +{ + fn describe() { + #[allow(non_snake_case)] + unsafe extern "C" fn invoke( + a: usize, + b: usize, + arg: ::Abi, + ) -> ::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Make sure all stack variables are converted before we + // convert `ret` as it may throw (for `Result`, for + // example) + let ret = { + let f: *const Fn(&A) -> R = + FatPtr { fields: (a, b) }.ptr; + let mut _stack = GlobalStack::new(); + let arg = ::ref_from_abi(arg, &mut _stack); + (*f)(&*arg) + }; + ret.return_abi(&mut GlobalStack::new()) + } + + inform(invoke:: as u32); + + unsafe extern fn destroy( + a: usize, + b: usize, + ) { + debug_assert!(a != 0, "should never destroy a Fn whose pointer is 0"); + drop(Box::from_raw(FatPtr:: R> { + fields: (a, b) + }.ptr)); + } + inform(destroy:: as u32); + + <&Self>::describe(); + } +} + +unsafe impl WasmClosure for FnMut(&A) -> R + where A: RefFromWasmAbi, + R: ReturnWasmAbi + 'static, +{ + fn describe() { + #[allow(non_snake_case)] + unsafe extern "C" fn invoke( + a: usize, + b: usize, + arg: ::Abi, + ) -> ::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Make sure all stack variables are converted before we + // convert `ret` as it may throw (for `Result`, for + // example) + let ret = { + let f: *const FnMut(&A) -> R = + FatPtr { fields: (a, b) }.ptr; + let f = f as *mut FnMut(&A) -> R; + let mut _stack = GlobalStack::new(); + let arg = ::ref_from_abi(arg, &mut _stack); + (*f)(&*arg) + }; + ret.return_abi(&mut GlobalStack::new()) + } + + inform(invoke:: as u32); + + unsafe extern fn destroy( + a: usize, + b: usize, + ) { + debug_assert!(a != 0, "should never destroy a FnMut whose pointer is 0"); + drop(Box::from_raw(FatPtr:: R> { + fields: (a, b) + }.ptr)); + } + inform(destroy:: as u32); + + <&mut Self>::describe(); + } +} + +#[allow(non_snake_case)] +impl WasmClosureFnOnce<(&A,), R> for T + where T: 'static + FnOnce(&A) -> R, + A: RefFromWasmAbi + 'static, + R: ReturnWasmAbi + 'static +{ + type FnMut = FnMut(&A) -> R; + + fn into_fn_mut(self) -> Box { + let mut me = Some(self); + Box::new(move |arg| { + let me = me.take().expect_throw("FnOnce called more than once"); + me(arg) + }) + } + + fn into_js_function(self) -> JsValue { + use std::rc::Rc; + use crate::__rt::WasmRefCell; + + let mut me = Some(self); + + let rc1 = Rc::new(WasmRefCell::new(None)); + let rc2 = rc1.clone(); + + let closure = Closure::wrap(Box::new(move |arg: &A| { + // Invoke ourself and get the result. + let me = me.take().expect_throw("FnOnce called more than once"); + let result = me(arg); + + // And then drop the `Rc` holding this function's `Closure` + // alive. + debug_assert_eq!(Rc::strong_count(&rc2), 1); + let option_closure = rc2.borrow_mut().take(); + debug_assert!(option_closure.is_some()); + drop(option_closure); + + result + }) as Box R>); + + let js_val = closure.as_ref().clone(); + + *rc1.borrow_mut() = Some(closure); + debug_assert_eq!(Rc::strong_count(&rc1), 2); + drop(rc1); + + js_val + } +} diff --git a/src/convert/closures.rs b/src/convert/closures.rs index 652e11a7..66174924 100644 --- a/src/convert/closures.rs +++ b/src/convert/closures.rs @@ -2,6 +2,7 @@ use core::mem; use crate::convert::slices::WasmSlice; use crate::convert::{FromWasmAbi, GlobalStack, IntoWasmAbi, ReturnWasmAbi, Stack}; +use crate::convert::RefFromWasmAbi; use crate::describe::{inform, WasmDescribe, FUNCTION}; use crate::throw_str; @@ -117,3 +118,97 @@ stack_closures! { (6 invoke6 invoke6_mut A B C D E F) (7 invoke7 invoke7_mut A B C D E F G) } + +impl<'a, 'b, A, R> IntoWasmAbi for &'a (Fn(&A) -> R + 'b) + where A: RefFromWasmAbi, + R: ReturnWasmAbi +{ + type Abi = WasmSlice; + + fn into_abi(self, _extra: &mut Stack) -> WasmSlice { + unsafe { + let (a, b): (usize, usize) = mem::transmute(self); + WasmSlice { ptr: a as u32, len: b as u32 } + } + } +} + +#[allow(non_snake_case)] +unsafe extern "C" fn invoke1_ref( + a: usize, + b: usize, + arg: ::Abi, +) -> ::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Scope all local variables before we call `return_abi` to + // ensure they're all destroyed as `return_abi` may throw + let ret = { + let f: &Fn(&A) -> R = mem::transmute((a, b)); + let mut _stack = GlobalStack::new(); + let arg = ::ref_from_abi(arg, &mut _stack); + f(&*arg) + }; + ret.return_abi(&mut GlobalStack::new()) +} + +impl<'a, A, R> WasmDescribe for Fn(&A) -> R + 'a + where A: RefFromWasmAbi, + R: ReturnWasmAbi, +{ + fn describe() { + inform(FUNCTION); + inform(invoke1_ref:: as u32); + inform(1); + <&A as WasmDescribe>::describe(); + ::describe(); + } +} + +impl<'a, 'b, A, R> IntoWasmAbi for &'a mut (FnMut(&A) -> R + 'b) + where A: RefFromWasmAbi, + R: ReturnWasmAbi +{ + type Abi = WasmSlice; + + fn into_abi(self, _extra: &mut Stack) -> WasmSlice { + unsafe { + let (a, b): (usize, usize) = mem::transmute(self); + WasmSlice { ptr: a as u32, len: b as u32 } + } + } +} + +#[allow(non_snake_case)] +unsafe extern "C" fn invoke1_mut_ref( + a: usize, + b: usize, + arg: ::Abi, +) -> ::Abi { + if a == 0 { + throw_str("closure invoked recursively or destroyed already"); + } + // Scope all local variables before we call `return_abi` to + // ensure they're all destroyed as `return_abi` may throw + let ret = { + let f: &mut FnMut(&A) -> R = mem::transmute((a, b)); + let mut _stack = GlobalStack::new(); + let arg = ::ref_from_abi(arg, &mut _stack); + f(&*arg) + }; + ret.return_abi(&mut GlobalStack::new()) +} + +impl<'a, A, R> WasmDescribe for FnMut(&A) -> R + 'a + where A: RefFromWasmAbi, + R: ReturnWasmAbi +{ + fn describe() { + inform(FUNCTION); + inform(invoke1_mut_ref:: as u32); + inform(1); + <&A as WasmDescribe>::describe(); + ::describe(); + } +} diff --git a/tests/wasm/closures.js b/tests/wasm/closures.js index 03d5d1f0..7acaa383 100644 --- a/tests/wasm/closures.js +++ b/tests/wasm/closures.js @@ -113,3 +113,9 @@ exports.calling_it_throws = a => { }; exports.call_val = f => f(); + +exports.pass_reference_first_arg_twice = (a, b, c) => { + b(a); + c(a); + a.free(); +}; diff --git a/tests/wasm/closures.rs b/tests/wasm/closures.rs index 4ce047f0..1e5af49e 100755 --- a/tests/wasm/closures.rs +++ b/tests/wasm/closures.rs @@ -90,6 +90,18 @@ extern "C" { #[wasm_bindgen(js_name = calling_it_throws)] fn call_val_throws(f: &JsValue) -> bool; + + fn pass_reference_first_arg_twice( + a: RefFirstArgument, + b: &Closure, + c: &Closure, + ); + #[wasm_bindgen(js_name = pass_reference_first_arg_twice)] + fn pass_reference_first_arg_twice2( + a: RefFirstArgument, + b: &mut FnMut(&RefFirstArgument), + c: &mut FnMut(&RefFirstArgument), + ); } #[wasm_bindgen_test] @@ -439,3 +451,74 @@ fn test_closure_returner() { Ok(o) } } + +#[wasm_bindgen] +pub struct RefFirstArgument { + contents: u32, +} + +#[wasm_bindgen_test] +fn reference_as_first_argument_builds_at_all() { + #[wasm_bindgen] + extern "C" { + fn ref_first_arg1(a: &Fn(&JsValue)); + fn ref_first_arg2(a: &mut FnMut(&JsValue)); + fn ref_first_arg3(a: &Closure); + fn ref_first_arg4(a: &Closure); + fn ref_first_custom1(a: &Fn(&RefFirstArgument)); + fn ref_first_custom2(a: &mut FnMut(&RefFirstArgument)); + fn ref_first_custom3(a: &Closure); + fn ref_first_custom4(a: &Closure); + } + + Closure::wrap(Box::new(|_: &JsValue| ()) as Box); + Closure::wrap(Box::new(|_: &JsValue| ()) as Box); + Closure::once(|_: &JsValue| ()); + Closure::once_into_js(|_: &JsValue| ()); + Closure::wrap(Box::new(|_: &RefFirstArgument| ()) as Box); + Closure::wrap(Box::new(|_: &RefFirstArgument| ()) as Box); + Closure::once(|_: &RefFirstArgument| ()); + Closure::once_into_js(|_: &RefFirstArgument| ()); +} + +#[wasm_bindgen_test] +fn reference_as_first_argument_works() { + let a = Rc::new(Cell::new(0)); + let b = { + let a = a.clone(); + Closure::once(move |x: &RefFirstArgument| { + assert_eq!(a.get(), 0); + assert_eq!(x.contents, 3); + a.set(a.get() + 1); + }) + }; + let c = { + let a = a.clone(); + Closure::once(move |x: &RefFirstArgument| { + assert_eq!(a.get(), 1); + assert_eq!(x.contents, 3); + a.set(a.get() + 1); + }) + }; + pass_reference_first_arg_twice(RefFirstArgument { contents: 3 }, &b, &c); + assert_eq!(a.get(), 2); +} + +#[wasm_bindgen_test] +fn reference_as_first_argument_works2() { + let a = Cell::new(0); + pass_reference_first_arg_twice2( + RefFirstArgument { contents: 3 }, + &mut |x: &RefFirstArgument| { + assert_eq!(a.get(), 0); + assert_eq!(x.contents, 3); + a.set(a.get() + 1); + }, + &mut |x: &RefFirstArgument| { + assert_eq!(a.get(), 1); + assert_eq!(x.contents, 3); + a.set(a.get() + 1); + }, + ); + assert_eq!(a.get(), 2); +} From b6317e3f24e159931ccae7a2ee761c5264cf3433 Mon Sep 17 00:00:00 2001 From: Caio Date: Mon, 1 Apr 2019 19:45:53 -0300 Subject: [PATCH 03/23] Add TS type for init fn --- crates/cli-support/src/js/mod.rs | 55 +++++++++++++++++++++---- crates/typescript-tests/run.sh | 7 ++++ crates/typescript-tests/src/web/init.ts | 3 ++ crates/typescript-tests/tsconfig.json | 2 +- 4 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 crates/typescript-tests/src/web/init.ts diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 4a9fabcd..9cee8101 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -311,6 +311,7 @@ impl<'a> Context<'a> { /// `--target no-modules`, `--target web`, or for bundlers. This is the very /// last step performed in `finalize`. fn finalize_js(&mut self, module_name: &str, needs_manual_start: bool) -> (String, String) { + let mut ts = self.typescript.clone(); let mut js = String::new(); if self.config.mode.no_modules() { js.push_str("(function() {\n"); @@ -318,7 +319,7 @@ impl<'a> Context<'a> { // Depending on the output mode, generate necessary glue to actually // import the wasm file in one way or another. - let mut init = String::new(); + let mut init = (String::new(), String::new()); match &self.config.mode { // In `--target no-modules` mode we need to both expose a name on // the global object as well as generate our own custom start @@ -371,6 +372,10 @@ impl<'a> Context<'a> { } } + let (init_js, init_ts) = init; + + ts.push_str(&init_ts); + // Emit all the JS for importing all our functionality js.push_str(&self.imports); js.push_str("\n"); @@ -382,7 +387,7 @@ impl<'a> Context<'a> { js.push_str("\n"); // Generate the initialization glue, if there was any - js.push_str(&init); + js.push_str(&init_js); js.push_str("\n"); js.push_str(&self.footer); js.push_str("\n"); @@ -394,7 +399,7 @@ impl<'a> Context<'a> { js = js.replace("\n\n\n", "\n\n"); } - (js, self.typescript.clone()) + (js, ts) } fn wire_up_initial_intrinsics(&mut self) -> Result<(), Error> { @@ -842,7 +847,34 @@ impl<'a> Context<'a> { Ok(()) } - fn gen_init(&mut self, module_name: &str, needs_manual_start: bool) -> String { + fn ts_for_init_fn(has_memory: bool) -> String { + let (memory_doc, memory_param) = if has_memory { + ( + "* @param {WebAssembly.Memory} maybe_memory\n", + ", maybe_memory: WebAssembly.Memory", + ) + } else { + ("", "") + }; + format!( + "\n\ + /**\n\ + * If `module_or_path` is {{RequestInfo}}, makes a request and\n\ + * for everything else, calls `WebAssembly.instantiate` directly.\n\ + *\n\ + * @param {{RequestInfo | BufferSource | WebAssembly.Module}} module_or_path\n\ + {}\ + *\n\ + * @returns {{Promise}}\n\ + */\n\ + export function init \ + (module_or_path: RequestInfo | BufferSource | WebAssembly.Module{}): Promise; + ", + memory_doc, memory_param + ) + } + + fn gen_init(&mut self, module_name: &str, needs_manual_start: bool) -> (String, String) { let mem = self.module.memories.get(self.memory); let (init_memory1, init_memory2) = if mem.import.is_some() { let mut memory = String::from("new WebAssembly.Memory({"); @@ -862,10 +894,16 @@ impl<'a> Context<'a> { } else { (String::new(), String::new()) }; + let init_memory_arg = if mem.import.is_some() { + ", maybe_memory" + } else { + "" + }; - format!( + let ts = Self::ts_for_init_fn(mem.import.is_some()); + let js = format!( "\ - function init(module_or_path, maybe_memory) {{ + function init(module_or_path{init_memory_arg}) {{ let result; const imports = {{ './{module}': __exports }}; if (module_or_path instanceof URL || typeof module_or_path === 'string' || module_or_path instanceof Request) {{ @@ -903,6 +941,7 @@ impl<'a> Context<'a> { }}); }} ", + init_memory_arg = init_memory_arg, module = module_name, init_memory1 = init_memory1, init_memory2 = init_memory2, @@ -911,7 +950,9 @@ impl<'a> Context<'a> { } else { "" }, - ) + ); + + (js, ts) } fn bind( diff --git a/crates/typescript-tests/run.sh b/crates/typescript-tests/run.sh index d6b03398..95a868a5 100755 --- a/crates/typescript-tests/run.sh +++ b/crates/typescript-tests/run.sh @@ -11,6 +11,13 @@ cargo run -p wasm-bindgen-cli --bin wasm-bindgen -- \ --out-dir pkg \ --typescript +mkdir pkg/web +cargo run -p wasm-bindgen-cli --bin wasm-bindgen -- \ + ../../target/wasm32-unknown-unknown/debug/typescript_tests.wasm \ + --out-dir pkg/web \ + --target web \ + --typescript + if [ ! -d node_modules ]; then npm install fi diff --git a/crates/typescript-tests/src/web/init.ts b/crates/typescript-tests/src/web/init.ts new file mode 100644 index 00000000..623efe72 --- /dev/null +++ b/crates/typescript-tests/src/web/init.ts @@ -0,0 +1,3 @@ +import * as wbg from '../../pkg/web/typescript_tests'; + +const init: Promise = wbg.init('.'); \ No newline at end of file diff --git a/crates/typescript-tests/tsconfig.json b/crates/typescript-tests/tsconfig.json index 90892979..3032c028 100644 --- a/crates/typescript-tests/tsconfig.json +++ b/crates/typescript-tests/tsconfig.json @@ -9,6 +9,6 @@ "baseUrl": "." }, "include": [ - "src/*.ts" + "src/**/*.ts" ] } From e3473f5e9efb8230697f22cca56afaa027b4bd48 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 2 Apr 2019 14:15:42 -0700 Subject: [PATCH 04/23] Fix instantiation with a `Module` This commit fixes the `init` function when passed a `WebAssembly.Module`. Upon closer reading of the [spec] we see there's two possible return values from `WebAssembly.instantiate`. If passed a `Module`, it will return only the `Instance`. If passed a buffer source, though, it'll return an object with the module/instance. The fix here is to check the result value is an `Instance`, and if so assume the input must have been a module so it's paired up in the output. Closes #1418 [spec]: http://webassembly.github.io/spec/js-api/index.html#webassembly-namespace --- crates/cli-support/src/js/mod.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index e8828d81..c44cd7cc 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -903,12 +903,12 @@ impl<'a> Context<'a> { let ts = Self::ts_for_init_fn(mem.import.is_some()); let js = format!( "\ - function init(module_or_path{init_memory_arg}) {{ + function init(module{init_memory_arg}) {{ let result; const imports = {{ './{module}': __exports }}; - if (module_or_path instanceof URL || typeof module_or_path === 'string' || module_or_path instanceof Request) {{ + if (module instanceof URL || typeof module === 'string' || module instanceof Request) {{ {init_memory2} - const response = fetch(module_or_path); + const response = fetch(module); if (typeof WebAssembly.instantiateStreaming === 'function') {{ result = WebAssembly.instantiateStreaming(response, imports) .catch(e => {{ @@ -928,9 +928,13 @@ impl<'a> Context<'a> { }} }} else {{ {init_memory1} - result = WebAssembly.instantiate(module_or_path, imports) - .then(instance => {{ - return {{ instance, module: module_or_path }}; + result = WebAssembly.instantiate(module, imports) + .then(result => {{ + if (result instanceof WebAssembly.Instance) {{ + return {{ instance: result, module }}; + }} else {{ + return result; + }} }}); }} return result.then(({{instance, module}}) => {{ From f48fdec21e41b10ba98c015b1b0d02c88acda8f6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 4 Apr 2019 09:56:16 -0700 Subject: [PATCH 05/23] Fix imported usage of `wasm_bindgen` macro Make sure it refers to `__wasm_bindgen_class_marker` via an absolute path! Closes #1422 --- crates/macro-support/src/parser.rs | 2 +- tests/wasm/classes.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index d94a4680..6ad5172e 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -896,7 +896,7 @@ fn prepare_for_impl_recursion( pound_token: Default::default(), style: syn::AttrStyle::Outer, bracket_token: Default::default(), - path: syn::Ident::new("__wasm_bindgen_class_marker", Span::call_site()).into(), + path: syn::parse_quote! { wasm_bindgen::prelude::__wasm_bindgen_class_marker }, tts: quote::quote! { (#class = #js_class) }.into(), }, ); diff --git a/tests/wasm/classes.rs b/tests/wasm/classes.rs index 024848b0..1b0ef953 100644 --- a/tests/wasm/classes.rs +++ b/tests/wasm/classes.rs @@ -459,3 +459,21 @@ pub fn option_class_assert_none(x: Option) { pub fn option_class_assert_some(x: Option) { assert_eq!(x.unwrap().0, 3); } + +mod works_in_module { + use wasm_bindgen::prelude::wasm_bindgen; + + #[wasm_bindgen] + pub struct WorksInModule(u32); + + #[wasm_bindgen] + impl WorksInModule { + #[wasm_bindgen(constructor)] + pub fn new() -> WorksInModule { + WorksInModule(1) + } + + pub fn foo(&self) { + } + } +} From dff9b9b1e347eb69b2f4d24ebdda746a26f14b77 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 4 Apr 2019 15:53:43 -0700 Subject: [PATCH 06/23] Don't put anything before ES module imports Because of some incorrect use of `js.push_str(..)`, we could sometimes emit code before the ES modules imports, which is syntactically invalid: const __exports = {}; import { Thing } from '...'; // Syntax error! This has been fixed by making sure that the correct `imports` or `imports_post` string is built up. We now also assert that the `js` string is empty at the location where we add imports if we're using ES modules. --- crates/cli-support/src/js/mod.rs | 9 +++++++-- crates/cli-support/src/lib.rs | 13 +++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index c44cd7cc..ae7b1b20 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -354,7 +354,8 @@ impl<'a> Context<'a> { | OutputMode::Node { experimental_modules: true, } => { - js.push_str(&format!("import * as wasm from './{}_bg';\n", module_name)); + self.imports + .push_str(&format!("import * as wasm from './{}_bg';\n", module_name)); if needs_manual_start { self.footer.push_str("wasm.__wbindgen_start();\n"); } @@ -365,7 +366,7 @@ impl<'a> Context<'a> { // expose the same initialization function as `--target no-modules` // as the default export of the module. OutputMode::Web => { - js.push_str("const __exports = {};\n"); + self.imports_post.push_str("const __exports = {};\n"); self.imports_post.push_str("let wasm;\n"); init = self.gen_init(&module_name, needs_manual_start); self.footer.push_str("export default init;\n"); @@ -377,6 +378,10 @@ impl<'a> Context<'a> { ts.push_str(&init_ts); // Emit all the JS for importing all our functionality + assert!( + !self.config.mode.uses_es_modules() || js.is_empty(), + "ES modules require imports to be at the start of the file" + ); js.push_str(&self.imports); js.push_str("\n"); js.push_str(&self.imports_post); diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index 45186593..5793b83b 100755 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -42,6 +42,19 @@ enum OutputMode { Node { experimental_modules: bool }, } +impl OutputMode { + fn uses_es_modules(&self) -> bool { + match self { + OutputMode::Bundler { .. } + | OutputMode::Web + | OutputMode::Node { + experimental_modules: true, + } => true, + _ => false, + } + } +} + enum Input { Path(PathBuf), Module(Module, String), From a9ad9a96dbda6d54c8cea660786f1759269853ca Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 5 Apr 2019 09:41:00 -0300 Subject: [PATCH 07/23] Update CONTRIBUTING to inform about code formatting --- guide/src/contributing/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/guide/src/contributing/index.md b/guide/src/contributing/index.md index dbd469ea..00a195ac 100644 --- a/guide/src/contributing/index.md +++ b/guide/src/contributing/index.md @@ -20,3 +20,7 @@ development. You may want to browse the [unpublished guide documentation] for as that is when WebAssembly support was introduced. [Install Node]. [Install Node]: https://nodejs.org/en/ + +## Code Formatting + +Although formatting rules are not mandatory, it is encouraged to run `cargo run` (`rustfmt`) with its default rules within a PR to maintain a more organized code base. If necessary, a PR with a single commit that formats the entire project is also welcome. \ No newline at end of file From 44738e049a1c9590e2101df2c993241218041cf1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 1 Apr 2019 11:09:57 -0700 Subject: [PATCH 08/23] Add warnings about UTF-16 vs UTF-8 strings This commit aims to address #1348 via a number of strategies: * Documentation is updated to warn about UTF-16 vs UTF-8 problems between JS and Rust. Notably documenting that `as_string` and handling of arguments is lossy when there are lone surrogates. * A `JsString::is_valid_utf16` method was added to test whether `as_string` is lossless or not. The intention is that most default behavior of `wasm-bindgen` will remain, but where necessary bindings will use `JsString` instead of `str`/`String` and will manually check for `is_valid_utf16` as necessary. It's also hypothesized that this is relatively rare and not too performance critical, so an optimized intrinsic for `is_valid_utf16` is not yet provided. Closes #1348 --- crates/js-sys/src/lib.rs | 31 +++++++++++++++++++++++++++ crates/js-sys/tests/wasm/JsString.rs | 12 +++++++++++ examples/without-a-bundler/index.html | 7 +++++- guide/src/reference/types/str.md | 27 +++++++++++++++++++++++ guide/src/reference/types/string.md | 3 +++ src/lib.rs | 10 +++++++++ 6 files changed, 89 insertions(+), 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 85fcab47..c96b6ae0 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -3522,6 +3522,37 @@ impl JsString { None } } + + /// Returns whether this string is a valid UTF-16 string. + /// + /// This is useful for learning whether `String::from(..)` will return a + /// lossless representation of the JS string. If this string contains + /// unpaired surrogates then `String::from` will succeed but it will be a + /// lossy representation of the JS string because unpaired surrogates will + /// become replacement characters. + /// + /// If this function returns `false` then to get a lossless representation + /// of the string you'll need to manually use the `iter` method (or the + /// `char_code_at` accessor) to view the raw character codes. + /// + /// For more information, see the documentation on [JS strings vs Rust + /// strings][docs] + /// + /// [docs]: https://rustwasm.github.io/docs/wasm-bindgen/reference/types/str.html + pub fn is_valid_utf16(&self) -> bool { + std::char::decode_utf16(self.iter()).all(|i| i.is_ok()) + } + + /// Returns an iterator over the `u16` character codes that make up this JS + /// string. + /// + /// This method will call `char_code_at` for each code in this JS string, + /// returning an iterator of the codes in sequence. + pub fn iter<'a>( + &'a self, + ) -> impl ExactSizeIterator + DoubleEndedIterator + 'a { + (0..self.length()).map(move |i| self.char_code_at(i) as u16) + } } impl PartialEq for JsString { diff --git a/crates/js-sys/tests/wasm/JsString.rs b/crates/js-sys/tests/wasm/JsString.rs index bb4a6ac0..c7f229f1 100644 --- a/crates/js-sys/tests/wasm/JsString.rs +++ b/crates/js-sys/tests/wasm/JsString.rs @@ -541,3 +541,15 @@ fn raw() { ); assert!(JsString::raw_0(&JsValue::null().unchecked_into()).is_err()); } + +#[wasm_bindgen_test] +fn is_valid_utf16() { + assert!(JsString::from("a").is_valid_utf16()); + assert!(JsString::from("").is_valid_utf16()); + assert!(JsString::from("🥑").is_valid_utf16()); + assert!(JsString::from("Why hello there this, 🥑, is 🥑 and is 🥑").is_valid_utf16()); + + assert!(JsString::from_char_code1(0x00).is_valid_utf16()); + assert!(!JsString::from_char_code1(0xd800).is_valid_utf16()); + assert!(!JsString::from_char_code1(0xdc00).is_valid_utf16()); +} diff --git a/examples/without-a-bundler/index.html b/examples/without-a-bundler/index.html index ee71e3d3..bb535278 100644 --- a/examples/without-a-bundler/index.html +++ b/examples/without-a-bundler/index.html @@ -25,7 +25,12 @@ // Also note that the promise, when resolved, yields the wasm module's // exports which is the same as importing the `*_bg` module in other // modes - await init('./pkg/without_a_bundler_bg.wasm'); + // await init('./pkg/without_a_bundler_bg.wasm'); + + const url = await fetch('http://localhost:8001/pkg/without_a_bundler_bg.wasm'); + const body = await url.arrayBuffer(); + const module = await WebAssembly.compile(body); + await init(module); // And afterwards we can use all the functionality defined in wasm. const result = add(1, 2); diff --git a/guide/src/reference/types/str.md b/guide/src/reference/types/str.md index 999bbc18..5de5f166 100644 --- a/guide/src/reference/types/str.md +++ b/guide/src/reference/types/str.md @@ -20,3 +20,30 @@ with handles to JavaScript string values, use the `js_sys::JsString` type. ```js {{#include ../../../../examples/guide-supported-types-examples/str.js}} ``` + +## UTF-16 vs UTF-8 + +Strings in JavaScript are encoded as UTF-16, but with one major exception: they +can contain unpaired surrogates. For some Unicode characters UTF-16 uses two +16-byte values. These are called "surrogate pairs" because they always come in +pairs. In JavaScript, it is possible for these surrogate pairs to be missing the +other half, creating an "unpaired surrogate". + +When passing a string from JavaScript to Rust, it uses the `TextEncoder` API to +convert from UTF-16 to UTF-8. This is normally perfectly fine... unless there +are unpaired surrogates. In that case it will replace the unpaired surrogates +with U+FFFD (�, the replacement character). That means the string in Rust is +now different from the string in JavaScript! + +If you want to guarantee that the Rust string is the same as the JavaScript +string, you should instead use `js_sys::JsString` (which keeps the string in +JavaScript and doesn't copy it into Rust). + +If you want to access the raw value of a JS string, you can use `JsString::iter`, +which returns an `Iterator`. This perfectly preserves everything +(including unpaired surrogates), but it does not do any encoding (so you +have to do that yourself!). + +If you simply want to ignore strings which contain unpaired surrogates, you can +use `JsString::is_valid_utf16` to test whether the string contains unpaired +surrogates or not. diff --git a/guide/src/reference/types/string.md b/guide/src/reference/types/string.md index 568e20b6..3b846704 100644 --- a/guide/src/reference/types/string.md +++ b/guide/src/reference/types/string.md @@ -8,6 +8,9 @@ Copies the string's contents back and forth between the JavaScript garbage-collected heap and the Wasm linear memory with `TextDecoder` and `TextEncoder` +> **Note**: Be sure to check out the [documentation for `str`](str.html) to +> learn about some caveats when working with strings between JS and Rust. + ## Example Rust Usage ```rust diff --git a/src/lib.rs b/src/lib.rs index 0cd5034b..1c1f78ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -260,6 +260,16 @@ impl JsValue { /// /// If this JS value is not an instance of a string or if it's not valid /// utf-8 then this returns `None`. + /// + /// # UTF-16 vs UTF-8 + /// + /// JavaScript strings in general are encoded as UTF-16, but Rust strings + /// are encoded as UTF-8. This can cause the Rust string to look a bit + /// different than the JS string sometimes. For more details see the + /// [documentation about the `str` type][caveats] which contains a few + /// caveats about the encodings. + /// + /// [caveats]: https://rustwasm.github.io/docs/wasm-bindgen/reference/types/str.html #[cfg(feature = "std")] pub fn as_string(&self) -> Option { unsafe { From e4400ac8b4f43006cb6a97ec9cf025e4284cbd95 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:35:14 -0700 Subject: [PATCH 09/23] Improve error message for non-copy struct fields Make sure the error message points to the type in question instead of to the `#[wasm_bindgen]` macro which can be overly confusing! --- crates/backend/src/codegen.rs | 39 ++++++++++++++++++++--- crates/macro/ui-tests/pub-not-copy.rs | 10 ++++++ crates/macro/ui-tests/pub-not-copy.stderr | 15 +++++++++ 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 crates/macro/ui-tests/pub-not-copy.rs create mode 100644 crates/macro/ui-tests/pub-not-copy.stderr diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index f53cbb9c..e3788a2c 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -291,11 +291,13 @@ impl ToTokens for ast::StructField { let ty = &self.ty; let getter = &self.getter; let setter = &self.setter; + + let assert_copy = quote! { assert_copy::<#ty>() }; + let assert_copy = respan(assert_copy, ty); (quote! { - #[no_mangle] #[doc(hidden)] - #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] #[allow(clippy::all)] + #[cfg_attr(all(target_arch = "wasm32", not(target_os = "emscripten")), no_mangle)] pub unsafe extern "C" fn #getter(js: u32) -> <#ty as wasm_bindgen::convert::IntoWasmAbi>::Abi { @@ -303,7 +305,7 @@ impl ToTokens for ast::StructField { use wasm_bindgen::convert::{GlobalStack, IntoWasmAbi}; fn assert_copy(){} - assert_copy::<#ty>(); + #assert_copy; let js = js as *mut WasmRefCell<#struct_name>; assert_not_null(js); @@ -714,7 +716,8 @@ impl ToTokens for ast::ImportType { () }; - }).to_tokens(tokens); + }) + .to_tokens(tokens); let deref_target = match self.extends.first() { Some(target) => quote! { #target }, @@ -1430,3 +1433,31 @@ impl<'a, T: ToTokens> ToTokens for Descriptor<'a, T> { .to_tokens(tokens); } } + +fn respan( + input: TokenStream, + span: &dyn ToTokens, +) -> TokenStream { + let mut first_span = Span::call_site(); + let mut last_span = Span::call_site(); + let mut spans = TokenStream::new(); + span.to_tokens(&mut spans); + + for (i, token) in spans.into_iter().enumerate() { + if i == 0 { + first_span = token.span(); + } + last_span = token.span(); + } + + let mut new_tokens = Vec::new(); + for (i, mut token) in input.into_iter().enumerate() { + if i == 0 { + token.set_span(first_span); + } else { + token.set_span(last_span); + } + new_tokens.push(token); + } + new_tokens.into_iter().collect() +} diff --git a/crates/macro/ui-tests/pub-not-copy.rs b/crates/macro/ui-tests/pub-not-copy.rs new file mode 100644 index 00000000..4c7cf0b3 --- /dev/null +++ b/crates/macro/ui-tests/pub-not-copy.rs @@ -0,0 +1,10 @@ +#![crate_type = "rlib"] + +extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct A { + pub field: String, +} diff --git a/crates/macro/ui-tests/pub-not-copy.stderr b/crates/macro/ui-tests/pub-not-copy.stderr new file mode 100644 index 00000000..95b597c4 --- /dev/null +++ b/crates/macro/ui-tests/pub-not-copy.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied + --> $DIR/pub-not-copy.rs:9:16 + | +9 | pub field: String, + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | +note: required by `__wbg_get_a_field::assert_copy` + --> $DIR/pub-not-copy.rs:7:1 + | +7 | #[wasm_bindgen] + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From b6d041e4d52cbf2763b6d49ced8f41296e27dc55 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:49:58 -0700 Subject: [PATCH 10/23] Remove debugging code accidentally added in #1416 --- examples/without-a-bundler/index.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/without-a-bundler/index.html b/examples/without-a-bundler/index.html index bb535278..ee71e3d3 100644 --- a/examples/without-a-bundler/index.html +++ b/examples/without-a-bundler/index.html @@ -25,12 +25,7 @@ // Also note that the promise, when resolved, yields the wasm module's // exports which is the same as importing the `*_bg` module in other // modes - // await init('./pkg/without_a_bundler_bg.wasm'); - - const url = await fetch('http://localhost:8001/pkg/without_a_bundler_bg.wasm'); - const body = await url.arrayBuffer(); - const module = await WebAssembly.compile(body); - await init(module); + await init('./pkg/without_a_bundler_bg.wasm'); // And afterwards we can use all the functionality defined in wasm. const result = add(1, 2); From 7e5e401076b094a3373c8cf8617cc9d9b8e09f3d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 8 Apr 2019 07:43:38 -0700 Subject: [PATCH 11/23] Add an accessor for the function table This commit adds an intrinsics to the `wasm_bindgen` crate which accesses the `WebAssembly.Table` which is the function table of the module. Eventually the thinking is that a module would import its own function table via native wasm functionality (via `anyref` and such), but until that's implemented let's add a binding for it ourselves! Closes #1427 --- crates/cli-support/src/js/mod.rs | 8 ++++++++ src/lib.rs | 7 +++++++ tests/wasm/api.js | 6 ++++++ tests/wasm/api.rs | 12 ++++++++++++ 4 files changed, 33 insertions(+) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index ae7b1b20..b1896fd4 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -783,6 +783,14 @@ impl<'a> Context<'a> { )) })?; + self.bind("__wbindgen_function_table", &|me| { + me.function_table_needed = true; + Ok(format!( + "function() {{ return {}; }}", + me.add_heap_object("wasm.__wbg_function_table") + )) + })?; + self.bind("__wbindgen_rethrow", &|me| { Ok(format!( "function(idx) {{ throw {}; }}", diff --git a/src/lib.rs b/src/lib.rs index 1c1f78ff..5aad3f2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -517,6 +517,7 @@ externs! { fn __wbindgen_memory() -> u32; fn __wbindgen_module() -> u32; + fn __wbindgen_function_table() -> u32; } } @@ -736,6 +737,12 @@ pub fn memory() -> JsValue { unsafe { JsValue::_new(__wbindgen_memory()) } } +/// Returns a handle to this wasm instance's `WebAssembly.Table` which is the +/// indirect function table used by Rust +pub fn function_table() -> JsValue { + unsafe { JsValue::_new(__wbindgen_function_table()) } +} + #[doc(hidden)] pub mod __rt { use core::cell::{Cell, UnsafeCell}; diff --git a/tests/wasm/api.js b/tests/wasm/api.js index 4c2dec0e..be59f28d 100644 --- a/tests/wasm/api.js +++ b/tests/wasm/api.js @@ -55,3 +55,9 @@ exports.debug_values = () => ([ () => (null), new Set(), ]); + +exports.assert_function_table = (x, i) => { + const rawWasm = require('wasm-bindgen-test_bg.js'); + assert.ok(x instanceof WebAssembly.Table); + assert.strictEqual(x.get(i), rawWasm.function_table_lookup); +}; diff --git a/tests/wasm/api.rs b/tests/wasm/api.rs index 92b7b21d..84b626e6 100644 --- a/tests/wasm/api.rs +++ b/tests/wasm/api.rs @@ -9,6 +9,7 @@ extern "C" { fn js_eq_works(); fn assert_null(v: JsValue); fn debug_values() -> JsValue; + fn assert_function_table(a: JsValue, b: usize); } #[wasm_bindgen_test] @@ -171,3 +172,14 @@ fn debug_output() { assert_eq!(format!("{:?}", test.unwrap()), expected); } } + +#[wasm_bindgen_test] +fn function_table_is() { + assert_function_table( + wasm_bindgen::function_table(), + function_table_lookup as usize, + ); +} + +#[no_mangle] +pub extern "C" fn function_table_lookup() {} From 02394724eaa841e20d67b318a38ab663d1fa647a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 10 Apr 2019 10:53:32 -0700 Subject: [PATCH 12/23] Bump to 0.2.41 --- CHANGELOG.md | 60 +++++++++++++++++++ Cargo.toml | 8 +-- crates/anyref-xform/Cargo.toml | 2 +- crates/backend/Cargo.toml | 4 +- crates/cli-support/Cargo.toml | 10 ++-- crates/cli/Cargo.toml | 6 +- crates/futures/Cargo.toml | 8 +-- crates/js-sys/Cargo.toml | 8 +-- crates/macro-support/Cargo.toml | 6 +- crates/macro/Cargo.toml | 4 +- crates/shared/Cargo.toml | 2 +- crates/test-macro/Cargo.toml | 2 +- crates/test/Cargo.toml | 10 ++-- crates/threads-xform/Cargo.toml | 2 +- crates/wasm-interpreter/Cargo.toml | 2 +- crates/web-sys/Cargo.toml | 12 ++-- crates/webidl/Cargo.toml | 4 +- examples/add/Cargo.toml | 2 +- examples/canvas/Cargo.toml | 4 +- examples/char/Cargo.toml | 2 +- examples/closures/Cargo.toml | 4 +- examples/console_log/Cargo.toml | 4 +- examples/dom/Cargo.toml | 2 +- examples/duck-typed-interfaces/Cargo.toml | 2 +- examples/fetch/Cargo.toml | 6 +- .../guide-supported-types-examples/Cargo.toml | 2 +- examples/hello_world/Cargo.toml | 2 +- examples/import_js/crate/Cargo.toml | 2 +- examples/julia_set/Cargo.toml | 2 +- examples/paint/Cargo.toml | 4 +- examples/performance/Cargo.toml | 2 +- examples/raytrace-parallel/Cargo.toml | 6 +- examples/request-animation-frame/Cargo.toml | 2 +- examples/todomvc/Cargo.toml | 4 +- examples/wasm-in-wasm/Cargo.toml | 4 +- examples/wasm2js/Cargo.toml | 2 +- examples/webaudio/Cargo.toml | 2 +- examples/webgl/Cargo.toml | 4 +- examples/without-a-bundler/Cargo.toml | 2 +- 39 files changed, 138 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47872006..553a9609 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,66 @@ Released YYYY-MM-DD. -------------------------------------------------------------------------------- +## 0.2.41 + +Released 2019-04-10. + +### Added + +* Initial support for transitive NPM dependencies has been added, although + support has not fully landed in `wasm-pack` yet so it's not 100% integrated. + [#1305](https://github.com/rustwasm/wasm-bindgen/pull/1305) + +* The `constructor` property of `Object` is now bound in `js-sys`. + [#1403](https://github.com/rustwasm/wasm-bindgen/pull/1403) + +* The `Closure` type now always implements `Debug`. + [#1408](https://github.com/rustwasm/wasm-bindgen/pull/1408) + +* Closures which take one `&T` argument are now supported. More implementations + may be added in the future, but for now it's just one argument closures. + [#1417](https://github.com/rustwasm/wasm-bindgen/pull/1417) + +* The TypeScript bindings for `--web` now expose the `init` function. + [#1412](https://github.com/rustwasm/wasm-bindgen/pull/1412) + +* A `js_sys::JsString::is_valid_utf16` method has been added to handle unpaired + surrogates in JS strings. Surrounding documentation has also been updated to + document this potential pitfall. + [#1416](https://github.com/rustwasm/wasm-bindgen/pull/1416) + +* A `wasm_bindgen::function_table()` function has been added to expose the + `WebAssembly.Table` and get access to it in wasm code. + [#1431](https://github.com/rustwasm/wasm-bindgen/pull/1431) + +### Fixed + +* Reexporting the `wasm_bindgen` macro in crates has been fixed. + [#1359](https://github.com/rustwasm/wasm-bindgen/pull/1359) + +* Returning `u32` to JS has been fixed where large `u32` values would show up in + JS as large negative numbers. + [#1401](https://github.com/rustwasm/wasm-bindgen/pull/1401) + +* Manual instantiation with `WebAssembly.Module` has been fixed. + [#1419](https://github.com/rustwasm/wasm-bindgen/pull/1419) + +* Error message for non-`Copy` public struct fields has been improved. + [#1430](https://github.com/rustwasm/wasm-bindgen/pull/1430) + +### Changed + +* Performance of passing strings to Rust in Node.js has been improved. + [#1391](https://github.com/rustwasm/wasm-bindgen/pull/1391) + +* Performance of `js_sys::try_iter` has been improved. + [#1393](https://github.com/rustwasm/wasm-bindgen/pull/1393) + +* Performance of using `TextEncoder#encodeInto` has been improved. + [#1414](https://github.com/rustwasm/wasm-bindgen/pull/1414) + +-------------------------------------------------------------------------------- + ## 0.2.40 Released 2019-03-21. diff --git a/Cargo.toml b/Cargo.toml index 68044f2c..96fd0230 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" readme = "README.md" @@ -35,13 +35,13 @@ strict-macro = ["wasm-bindgen-macro/strict-macro"] 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.40" } +wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.41" } serde = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -js-sys = { path = 'crates/js-sys', version = '0.3.17' } -wasm-bindgen-test = { path = 'crates/test', version = '=0.2.40' } +js-sys = { path = 'crates/js-sys', version = '0.3.18' } +wasm-bindgen-test = { path = 'crates/test', version = '=0.2.41' } serde_derive = "1.0" wasm-bindgen-test-crate-a = { path = 'tests/crates/a', version = '0.1' } wasm-bindgen-test-crate-b = { path = 'tests/crates/b', version = '0.1' } diff --git a/crates/anyref-xform/Cargo.toml b/crates/anyref-xform/Cargo.toml index 7c8e5419..d5617c2a 100644 --- a/crates/anyref-xform/Cargo.toml +++ b/crates/anyref-xform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-anyref-xform" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/anyref-xform" diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index 77489235..e2259ce5 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-backend" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend" @@ -22,4 +22,4 @@ log = "0.4" proc-macro2 = "0.4.8" quote = '0.6' syn = { version = '0.15', features = ['full'] } -wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" } +wasm-bindgen-shared = { path = "../shared", version = "=0.2.41" } diff --git a/crates/cli-support/Cargo.toml b/crates/cli-support/Cargo.toml index 66082c09..b31dd1d2 100644 --- a/crates/cli-support/Cargo.toml +++ b/crates/cli-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-cli-support" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli-support" @@ -19,7 +19,7 @@ rustc-demangle = "0.1.13" serde_json = "1.0" tempfile = "3.0" walrus = "0.5.0" -wasm-bindgen-anyref-xform = { path = '../anyref-xform', version = '=0.2.40' } -wasm-bindgen-shared = { path = "../shared", version = '=0.2.40' } -wasm-bindgen-threads-xform = { path = '../threads-xform', version = '=0.2.40' } -wasm-bindgen-wasm-interpreter = { path = "../wasm-interpreter", version = '=0.2.40' } +wasm-bindgen-anyref-xform = { path = '../anyref-xform', version = '=0.2.41' } +wasm-bindgen-shared = { path = "../shared", version = '=0.2.41' } +wasm-bindgen-threads-xform = { path = '../threads-xform', version = '=0.2.41' } +wasm-bindgen-wasm-interpreter = { path = "../wasm-interpreter", version = '=0.2.41' } diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 478e661a..ae5ab3c6 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-cli" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli" @@ -25,8 +25,8 @@ serde = { version = "1.0", features = ['derive'] } serde_derive = "1.0" serde_json = "1.0" walrus = "0.5" -wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.40" } -wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" } +wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.41" } +wasm-bindgen-shared = { path = "../shared", version = "=0.2.41" } [dev-dependencies] assert_cmd = "0.11" diff --git a/crates/futures/Cargo.toml b/crates/futures/Cargo.toml index 097541b5..d982e9bd 100644 --- a/crates/futures/Cargo.toml +++ b/crates/futures/Cargo.toml @@ -7,13 +7,13 @@ 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.3.17" +version = "0.3.18" edition = "2018" [dependencies] futures = "0.1.20" -js-sys = { path = "../js-sys", version = '0.3.17' } -wasm-bindgen = { path = "../..", version = '0.2.40' } +js-sys = { path = "../js-sys", version = '0.3.18' } +wasm-bindgen = { path = "../..", version = '0.2.41' } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = { path = '../test', version = '0.2.40' } +wasm-bindgen-test = { path = '../test', version = '0.2.41' } diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index 2cad468e..f4a27b7d 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "js-sys" -version = "0.3.17" +version = "0.3.18" authors = ["The wasm-bindgen Developers"] readme = "./README.md" categories = ["wasm"] @@ -19,9 +19,9 @@ test = false doctest = false [dependencies] -wasm-bindgen = { path = "../..", version = "0.2.40" } +wasm-bindgen = { path = "../..", version = "0.2.41" } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] futures = "0.1.20" -wasm-bindgen-test = { path = '../test', version = '=0.2.40' } -wasm-bindgen-futures = { path = '../futures', version = '=0.3.17' } +wasm-bindgen-test = { path = '../test', version = '=0.2.41' } +wasm-bindgen-futures = { path = '../futures', version = '=0.3.18' } diff --git a/crates/macro-support/Cargo.toml b/crates/macro-support/Cargo.toml index 72b5185c..f0863c95 100644 --- a/crates/macro-support/Cargo.toml +++ b/crates/macro-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-macro-support" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support" @@ -20,5 +20,5 @@ strict-macro = [] syn = { version = '0.15.0', features = ['visit'] } quote = '0.6' proc-macro2 = "0.4.9" -wasm-bindgen-backend = { path = "../backend", version = "=0.2.40" } -wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" } +wasm-bindgen-backend = { path = "../backend", version = "=0.2.41" } +wasm-bindgen-shared = { path = "../shared", version = "=0.2.41" } diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml index 1400256a..6fb253ef 100644 --- a/crates/macro/Cargo.toml +++ b/crates/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-macro" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro" @@ -20,5 +20,5 @@ xxx_debug_only_print_generated_code = [] strict-macro = ["wasm-bindgen-macro-support/strict-macro"] [dependencies] -wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.40" } +wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.41" } quote = "0.6" diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index 9eb60b65..88227f20 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-shared" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared" diff --git a/crates/test-macro/Cargo.toml b/crates/test-macro/Cargo.toml index 09135e50..428dbb07 100644 --- a/crates/test-macro/Cargo.toml +++ b/crates/test-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-test-macro" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] description = "Internal testing macro for wasm-bindgen" license = "MIT/Apache-2.0" diff --git a/crates/test/Cargo.toml b/crates/test/Cargo.toml index 3eb2c901..3609a74e 100644 --- a/crates/test/Cargo.toml +++ b/crates/test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-test" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] description = "Internal testing crate for wasm-bindgen" license = "MIT/Apache-2.0" @@ -10,11 +10,11 @@ edition = "2018" [dependencies] console_error_panic_hook = '0.1' futures = "0.1" -js-sys = { path = '../js-sys', version = '0.3.17' } +js-sys = { path = '../js-sys', version = '0.3.18' } scoped-tls = "1.0" -wasm-bindgen = { path = '../..', version = '0.2.40' } -wasm-bindgen-futures = { path = '../futures', version = '0.3.17' } -wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.40' } +wasm-bindgen = { path = '../..', version = '0.2.41' } +wasm-bindgen-futures = { path = '../futures', version = '0.3.18' } +wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.41' } [lib] test = false diff --git a/crates/threads-xform/Cargo.toml b/crates/threads-xform/Cargo.toml index c2b9a410..951ce979 100644 --- a/crates/threads-xform/Cargo.toml +++ b/crates/threads-xform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-threads-xform" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/threads-xform" diff --git a/crates/wasm-interpreter/Cargo.toml b/crates/wasm-interpreter/Cargo.toml index 76b8d898..4d163884 100644 --- a/crates/wasm-interpreter/Cargo.toml +++ b/crates/wasm-interpreter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-wasm-interpreter" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/wasm-interpreter" diff --git a/crates/web-sys/Cargo.toml b/crates/web-sys/Cargo.toml index 72718f06..e94a1794 100644 --- a/crates/web-sys/Cargo.toml +++ b/crates/web-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "web-sys" -version = "0.3.17" +version = "0.3.18" authors = ["The wasm-bindgen Developers"] readme = "./README.md" homepage = "https://rustwasm.github.io/wasm-bindgen/web-sys/index.html" @@ -22,17 +22,17 @@ test = false [build-dependencies] env_logger = "0.6.0" failure = "0.1.2" -wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.40" } +wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.41" } sourcefile = "0.1" [dependencies] -wasm-bindgen = { path = "../..", version = "0.2.40" } -js-sys = { path = '../js-sys', version = '0.3.17' } +wasm-bindgen = { path = "../..", version = "0.2.41" } +js-sys = { path = '../js-sys', version = '0.3.18' } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] futures = "0.1" -wasm-bindgen-test = { path = '../test', version = '0.2.40' } -wasm-bindgen-futures = { path = '../futures', version = '0.3.17' } +wasm-bindgen-test = { path = '../test', version = '0.2.41' } +wasm-bindgen-futures = { path = '../futures', version = '0.3.18' } # This list is generated by passing `__WASM_BINDGEN_DUMP_FEATURES=foo` when # compiling this crate which dumps the total list of features to a file called diff --git a/crates/webidl/Cargo.toml b/crates/webidl/Cargo.toml index 91ed2f0b..ba71c45f 100644 --- a/crates/webidl/Cargo.toml +++ b/crates/webidl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-webidl" -version = "0.2.40" +version = "0.2.41" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" categories = ["wasm"] @@ -19,5 +19,5 @@ log = "0.4.1" proc-macro2 = "0.4.8" quote = '0.6' syn = { version = '0.15', features = ['full'] } -wasm-bindgen-backend = { version = "=0.2.40", path = "../backend" } +wasm-bindgen-backend = { version = "=0.2.41", path = "../backend" } weedle = "0.8" diff --git a/examples/add/Cargo.toml b/examples/add/Cargo.toml index f1b3dff9..563315b2 100644 --- a/examples/add/Cargo.toml +++ b/examples/add/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/canvas/Cargo.toml b/examples/canvas/Cargo.toml index 5a4dc531..d3696c03 100644 --- a/examples/canvas/Cargo.toml +++ b/examples/canvas/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.17" -wasm-bindgen = "0.2.40" +js-sys = "0.3.18" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/char/Cargo.toml b/examples/char/Cargo.toml index 2f708ec2..4ceaeab4 100644 --- a/examples/char/Cargo.toml +++ b/examples/char/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/closures/Cargo.toml b/examples/closures/Cargo.toml index 8ce7cb01..ddf82731 100644 --- a/examples/closures/Cargo.toml +++ b/examples/closures/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" -js-sys = "0.3.17" +wasm-bindgen = "0.2.41" +js-sys = "0.3.18" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/console_log/Cargo.toml b/examples/console_log/Cargo.toml index b4696e5c..cb34ae5a 100644 --- a/examples/console_log/Cargo.toml +++ b/examples/console_log/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" -web-sys = { version = "0.3.17", features = ['console'] } +wasm-bindgen = "0.2.41" +web-sys = { version = "0.3.18", features = ['console'] } diff --git a/examples/dom/Cargo.toml b/examples/dom/Cargo.toml index 6b584800..07728839 100644 --- a/examples/dom/Cargo.toml +++ b/examples/dom/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/duck-typed-interfaces/Cargo.toml b/examples/duck-typed-interfaces/Cargo.toml index 82863a93..fcccf0e5 100644 --- a/examples/duck-typed-interfaces/Cargo.toml +++ b/examples/duck-typed-interfaces/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/fetch/Cargo.toml b/examples/fetch/Cargo.toml index eee40154..f49e08a3 100644 --- a/examples/fetch/Cargo.toml +++ b/examples/fetch/Cargo.toml @@ -9,9 +9,9 @@ crate-type = ["cdylib"] [dependencies] futures = "0.1.20" -wasm-bindgen = { version = "0.2.40", features = ["serde-serialize"] } -js-sys = "0.3.17" -wasm-bindgen-futures = "0.3.17" +wasm-bindgen = { version = "0.2.41", features = ["serde-serialize"] } +js-sys = "0.3.18" +wasm-bindgen-futures = "0.3.18" serde = { version = "1.0.80", features = ["derive"] } serde_derive = "^1.0.59" diff --git a/examples/guide-supported-types-examples/Cargo.toml b/examples/guide-supported-types-examples/Cargo.toml index 4426b45b..3cf9253a 100644 --- a/examples/guide-supported-types-examples/Cargo.toml +++ b/examples/guide-supported-types-examples/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml index 32dfc572..99046b37 100644 --- a/examples/hello_world/Cargo.toml +++ b/examples/hello_world/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/import_js/crate/Cargo.toml b/examples/import_js/crate/Cargo.toml index 4cc846e0..1d2ce7dc 100644 --- a/examples/import_js/crate/Cargo.toml +++ b/examples/import_js/crate/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/julia_set/Cargo.toml b/examples/julia_set/Cargo.toml index a532ba89..850d3d80 100644 --- a/examples/julia_set/Cargo.toml +++ b/examples/julia_set/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/paint/Cargo.toml b/examples/paint/Cargo.toml index 61b425b0..94faaa8f 100644 --- a/examples/paint/Cargo.toml +++ b/examples/paint/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.17" -wasm-bindgen = "0.2.40" +js-sys = "0.3.18" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/performance/Cargo.toml b/examples/performance/Cargo.toml index d933122f..117a537b 100644 --- a/examples/performance/Cargo.toml +++ b/examples/performance/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" humantime = "1" [dependencies.web-sys] diff --git a/examples/raytrace-parallel/Cargo.toml b/examples/raytrace-parallel/Cargo.toml index 26a42fe4..37687bfc 100644 --- a/examples/raytrace-parallel/Cargo.toml +++ b/examples/raytrace-parallel/Cargo.toml @@ -10,10 +10,10 @@ crate-type = ["cdylib"] [dependencies] console_error_panic_hook = "0.1" futures = "0.1" -js-sys = "0.3.17" +js-sys = "0.3.18" raytracer = { git = 'https://github.com/alexcrichton/raytracer', branch = 'update-deps' } -wasm-bindgen = { version = "0.2.40", features = ['serde-serialize'] } -wasm-bindgen-futures = "0.3.17" +wasm-bindgen = { version = "0.2.41", features = ['serde-serialize'] } +wasm-bindgen-futures = "0.3.18" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/request-animation-frame/Cargo.toml b/examples/request-animation-frame/Cargo.toml index 5cd41996..36a965d3 100644 --- a/examples/request-animation-frame/Cargo.toml +++ b/examples/request-animation-frame/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/todomvc/Cargo.toml b/examples/todomvc/Cargo.toml index 32ff302e..760fb862 100644 --- a/examples/todomvc/Cargo.toml +++ b/examples/todomvc/Cargo.toml @@ -11,8 +11,8 @@ crate-type = ["cdylib"] askama = "0.7.2" [dependencies] -js-sys = "0.3.17" -wasm-bindgen = "0.2.40" +js-sys = "0.3.18" +wasm-bindgen = "0.2.41" askama = "0.7.2" console_error_panic_hook = "0.1.5" diff --git a/examples/wasm-in-wasm/Cargo.toml b/examples/wasm-in-wasm/Cargo.toml index 817b3e90..80ed879c 100644 --- a/examples/wasm-in-wasm/Cargo.toml +++ b/examples/wasm-in-wasm/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" -js-sys = "0.3.17" +wasm-bindgen = "0.2.41" +js-sys = "0.3.18" diff --git a/examples/wasm2js/Cargo.toml b/examples/wasm2js/Cargo.toml index 5c100132..1dc3a27f 100644 --- a/examples/wasm2js/Cargo.toml +++ b/examples/wasm2js/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" diff --git a/examples/webaudio/Cargo.toml b/examples/webaudio/Cargo.toml index 9e6a03b6..3950e4d1 100644 --- a/examples/webaudio/Cargo.toml +++ b/examples/webaudio/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/webgl/Cargo.toml b/examples/webgl/Cargo.toml index a0031931..71c632c9 100644 --- a/examples/webgl/Cargo.toml +++ b/examples/webgl/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.17" -wasm-bindgen = "0.2.40" +js-sys = "0.3.18" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/without-a-bundler/Cargo.toml b/examples/without-a-bundler/Cargo.toml index 0196551f..9bc3e181 100644 --- a/examples/without-a-bundler/Cargo.toml +++ b/examples/without-a-bundler/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.40" +wasm-bindgen = "0.2.41" [dependencies.web-sys] version = "0.3.4" From 3906e4066d3873619603f3a662bb09e8f754e6d1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Apr 2019 07:25:27 -0700 Subject: [PATCH 13/23] Fix a bug using `encodeInto` truncating strings The last write accidentally wasn't accounted for in the returned length of the string and we unfortunately don't have any test coverage of `encodeInto` since it requires Firefox nightly right now (and doesn't work in Node yet). Closes #1436 --- crates/cli-support/src/js/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index b1896fd4..d9f02ad6 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1364,11 +1364,11 @@ impl<'a> Context<'a> { while (true) {{ const view = getUint8Memory().subarray(ptr + writeOffset, ptr + size); const {{ read, written }} = cachedTextEncoder.encodeInto(arg, view); + writeOffset += written; if (read === arg.length) {{ break; }} arg = arg.substring(read); - writeOffset += written; ptr = wasm.__wbindgen_realloc(ptr, size, size += arg.length * 3); }} WASM_VECTOR_LEN = writeOffset; From df6e15e3ab56ea1237fb2b0a9964fd6aafeb73ca Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Apr 2019 07:39:45 -0700 Subject: [PATCH 14/23] Bump to 0.2.42 --- CHANGELOG.md | 12 ++++++++++++ Cargo.toml | 8 ++++---- crates/anyref-xform/Cargo.toml | 2 +- crates/backend/Cargo.toml | 4 ++-- crates/cli-support/Cargo.toml | 10 +++++----- crates/cli/Cargo.toml | 6 +++--- crates/futures/Cargo.toml | 8 ++++---- crates/js-sys/Cargo.toml | 8 ++++---- crates/macro-support/Cargo.toml | 6 +++--- crates/macro/Cargo.toml | 4 ++-- crates/shared/Cargo.toml | 2 +- crates/test-macro/Cargo.toml | 2 +- crates/test/Cargo.toml | 10 +++++----- crates/threads-xform/Cargo.toml | 2 +- crates/wasm-interpreter/Cargo.toml | 2 +- crates/web-sys/Cargo.toml | 12 ++++++------ crates/webidl/Cargo.toml | 4 ++-- examples/add/Cargo.toml | 2 +- examples/canvas/Cargo.toml | 4 ++-- examples/char/Cargo.toml | 2 +- examples/closures/Cargo.toml | 4 ++-- examples/console_log/Cargo.toml | 4 ++-- examples/dom/Cargo.toml | 2 +- examples/duck-typed-interfaces/Cargo.toml | 2 +- examples/fetch/Cargo.toml | 6 +++--- examples/guide-supported-types-examples/Cargo.toml | 2 +- examples/hello_world/Cargo.toml | 2 +- examples/import_js/crate/Cargo.toml | 2 +- examples/julia_set/Cargo.toml | 2 +- examples/paint/Cargo.toml | 4 ++-- examples/performance/Cargo.toml | 2 +- examples/raytrace-parallel/Cargo.toml | 6 +++--- examples/request-animation-frame/Cargo.toml | 2 +- examples/todomvc/Cargo.toml | 4 ++-- examples/wasm-in-wasm/Cargo.toml | 4 ++-- examples/wasm2js/Cargo.toml | 2 +- examples/webaudio/Cargo.toml | 2 +- examples/webgl/Cargo.toml | 4 ++-- examples/without-a-bundler/Cargo.toml | 2 +- 39 files changed, 90 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 553a9609..ddb5c2d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,18 @@ Released YYYY-MM-DD. -------------------------------------------------------------------------------- +## 0.2.42 + +Released 2019-04-11. + +### Fixed + +* Fixed an issue in Firefox where using `encodeInto` accidentally caused empty + strings to keep getting passed to Rust. + [#1434](https://github.com/rustwasm/wasm-bindgen/pull/1434) + +-------------------------------------------------------------------------------- + ## 0.2.41 Released 2019-04-10. diff --git a/Cargo.toml b/Cargo.toml index 96fd0230..67ddabbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" readme = "README.md" @@ -35,13 +35,13 @@ strict-macro = ["wasm-bindgen-macro/strict-macro"] 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.41" } +wasm-bindgen-macro = { path = "crates/macro", version = "=0.2.42" } serde = { version = "1.0", optional = true } serde_json = { version = "1.0", optional = true } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -js-sys = { path = 'crates/js-sys', version = '0.3.18' } -wasm-bindgen-test = { path = 'crates/test', version = '=0.2.41' } +js-sys = { path = 'crates/js-sys', version = '0.3.19' } +wasm-bindgen-test = { path = 'crates/test', version = '=0.2.42' } serde_derive = "1.0" wasm-bindgen-test-crate-a = { path = 'tests/crates/a', version = '0.1' } wasm-bindgen-test-crate-b = { path = 'tests/crates/b', version = '0.1' } diff --git a/crates/anyref-xform/Cargo.toml b/crates/anyref-xform/Cargo.toml index d5617c2a..e6afb759 100644 --- a/crates/anyref-xform/Cargo.toml +++ b/crates/anyref-xform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-anyref-xform" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/anyref-xform" diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index e2259ce5..1ad908c5 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-backend" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend" @@ -22,4 +22,4 @@ log = "0.4" proc-macro2 = "0.4.8" quote = '0.6' syn = { version = '0.15', features = ['full'] } -wasm-bindgen-shared = { path = "../shared", version = "=0.2.41" } +wasm-bindgen-shared = { path = "../shared", version = "=0.2.42" } diff --git a/crates/cli-support/Cargo.toml b/crates/cli-support/Cargo.toml index b31dd1d2..c31be03f 100644 --- a/crates/cli-support/Cargo.toml +++ b/crates/cli-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-cli-support" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli-support" @@ -19,7 +19,7 @@ rustc-demangle = "0.1.13" serde_json = "1.0" tempfile = "3.0" walrus = "0.5.0" -wasm-bindgen-anyref-xform = { path = '../anyref-xform', version = '=0.2.41' } -wasm-bindgen-shared = { path = "../shared", version = '=0.2.41' } -wasm-bindgen-threads-xform = { path = '../threads-xform', version = '=0.2.41' } -wasm-bindgen-wasm-interpreter = { path = "../wasm-interpreter", version = '=0.2.41' } +wasm-bindgen-anyref-xform = { path = '../anyref-xform', version = '=0.2.42' } +wasm-bindgen-shared = { path = "../shared", version = '=0.2.42' } +wasm-bindgen-threads-xform = { path = '../threads-xform', version = '=0.2.42' } +wasm-bindgen-wasm-interpreter = { path = "../wasm-interpreter", version = '=0.2.42' } diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index ae5ab3c6..5635da9c 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-cli" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/cli" @@ -25,8 +25,8 @@ serde = { version = "1.0", features = ['derive'] } serde_derive = "1.0" serde_json = "1.0" walrus = "0.5" -wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.41" } -wasm-bindgen-shared = { path = "../shared", version = "=0.2.41" } +wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.42" } +wasm-bindgen-shared = { path = "../shared", version = "=0.2.42" } [dev-dependencies] assert_cmd = "0.11" diff --git a/crates/futures/Cargo.toml b/crates/futures/Cargo.toml index d982e9bd..9e6072ec 100644 --- a/crates/futures/Cargo.toml +++ b/crates/futures/Cargo.toml @@ -7,13 +7,13 @@ 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.3.18" +version = "0.3.19" edition = "2018" [dependencies] futures = "0.1.20" -js-sys = { path = "../js-sys", version = '0.3.18' } -wasm-bindgen = { path = "../..", version = '0.2.41' } +js-sys = { path = "../js-sys", version = '0.3.19' } +wasm-bindgen = { path = "../..", version = '0.2.42' } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] -wasm-bindgen-test = { path = '../test', version = '0.2.41' } +wasm-bindgen-test = { path = '../test', version = '0.2.42' } diff --git a/crates/js-sys/Cargo.toml b/crates/js-sys/Cargo.toml index f4a27b7d..41bd9b2c 100644 --- a/crates/js-sys/Cargo.toml +++ b/crates/js-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "js-sys" -version = "0.3.18" +version = "0.3.19" authors = ["The wasm-bindgen Developers"] readme = "./README.md" categories = ["wasm"] @@ -19,9 +19,9 @@ test = false doctest = false [dependencies] -wasm-bindgen = { path = "../..", version = "0.2.41" } +wasm-bindgen = { path = "../..", version = "0.2.42" } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] futures = "0.1.20" -wasm-bindgen-test = { path = '../test', version = '=0.2.41' } -wasm-bindgen-futures = { path = '../futures', version = '=0.3.18' } +wasm-bindgen-test = { path = '../test', version = '=0.2.42' } +wasm-bindgen-futures = { path = '../futures', version = '=0.3.19' } diff --git a/crates/macro-support/Cargo.toml b/crates/macro-support/Cargo.toml index f0863c95..83ce0c10 100644 --- a/crates/macro-support/Cargo.toml +++ b/crates/macro-support/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-macro-support" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support" @@ -20,5 +20,5 @@ strict-macro = [] syn = { version = '0.15.0', features = ['visit'] } quote = '0.6' proc-macro2 = "0.4.9" -wasm-bindgen-backend = { path = "../backend", version = "=0.2.41" } -wasm-bindgen-shared = { path = "../shared", version = "=0.2.41" } +wasm-bindgen-backend = { path = "../backend", version = "=0.2.42" } +wasm-bindgen-shared = { path = "../shared", version = "=0.2.42" } diff --git a/crates/macro/Cargo.toml b/crates/macro/Cargo.toml index 6fb253ef..7a150e7f 100644 --- a/crates/macro/Cargo.toml +++ b/crates/macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-macro" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro" @@ -20,5 +20,5 @@ xxx_debug_only_print_generated_code = [] strict-macro = ["wasm-bindgen-macro-support/strict-macro"] [dependencies] -wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.41" } +wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.42" } quote = "0.6" diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index 88227f20..d99424bb 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-shared" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared" diff --git a/crates/test-macro/Cargo.toml b/crates/test-macro/Cargo.toml index 428dbb07..fefdd391 100644 --- a/crates/test-macro/Cargo.toml +++ b/crates/test-macro/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-test-macro" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] description = "Internal testing macro for wasm-bindgen" license = "MIT/Apache-2.0" diff --git a/crates/test/Cargo.toml b/crates/test/Cargo.toml index 3609a74e..b60c5715 100644 --- a/crates/test/Cargo.toml +++ b/crates/test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-test" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] description = "Internal testing crate for wasm-bindgen" license = "MIT/Apache-2.0" @@ -10,11 +10,11 @@ edition = "2018" [dependencies] console_error_panic_hook = '0.1' futures = "0.1" -js-sys = { path = '../js-sys', version = '0.3.18' } +js-sys = { path = '../js-sys', version = '0.3.19' } scoped-tls = "1.0" -wasm-bindgen = { path = '../..', version = '0.2.41' } -wasm-bindgen-futures = { path = '../futures', version = '0.3.18' } -wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.41' } +wasm-bindgen = { path = '../..', version = '0.2.42' } +wasm-bindgen-futures = { path = '../futures', version = '0.3.19' } +wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.42' } [lib] test = false diff --git a/crates/threads-xform/Cargo.toml b/crates/threads-xform/Cargo.toml index 951ce979..ab0dd139 100644 --- a/crates/threads-xform/Cargo.toml +++ b/crates/threads-xform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-threads-xform" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/threads-xform" diff --git a/crates/wasm-interpreter/Cargo.toml b/crates/wasm-interpreter/Cargo.toml index 4d163884..54d08aca 100644 --- a/crates/wasm-interpreter/Cargo.toml +++ b/crates/wasm-interpreter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-wasm-interpreter" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" repository = "https://github.com/rustwasm/wasm-bindgen/tree/master/crates/wasm-interpreter" diff --git a/crates/web-sys/Cargo.toml b/crates/web-sys/Cargo.toml index e94a1794..557f5381 100644 --- a/crates/web-sys/Cargo.toml +++ b/crates/web-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "web-sys" -version = "0.3.18" +version = "0.3.19" authors = ["The wasm-bindgen Developers"] readme = "./README.md" homepage = "https://rustwasm.github.io/wasm-bindgen/web-sys/index.html" @@ -22,17 +22,17 @@ test = false [build-dependencies] env_logger = "0.6.0" failure = "0.1.2" -wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.41" } +wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.42" } sourcefile = "0.1" [dependencies] -wasm-bindgen = { path = "../..", version = "0.2.41" } -js-sys = { path = '../js-sys', version = '0.3.18' } +wasm-bindgen = { path = "../..", version = "0.2.42" } +js-sys = { path = '../js-sys', version = '0.3.19' } [target.'cfg(target_arch = "wasm32")'.dev-dependencies] futures = "0.1" -wasm-bindgen-test = { path = '../test', version = '0.2.41' } -wasm-bindgen-futures = { path = '../futures', version = '0.3.18' } +wasm-bindgen-test = { path = '../test', version = '0.2.42' } +wasm-bindgen-futures = { path = '../futures', version = '0.3.19' } # This list is generated by passing `__WASM_BINDGEN_DUMP_FEATURES=foo` when # compiling this crate which dumps the total list of features to a file called diff --git a/crates/webidl/Cargo.toml b/crates/webidl/Cargo.toml index ba71c45f..5f841c3d 100644 --- a/crates/webidl/Cargo.toml +++ b/crates/webidl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-bindgen-webidl" -version = "0.2.41" +version = "0.2.42" authors = ["The wasm-bindgen Developers"] license = "MIT/Apache-2.0" categories = ["wasm"] @@ -19,5 +19,5 @@ log = "0.4.1" proc-macro2 = "0.4.8" quote = '0.6' syn = { version = '0.15', features = ['full'] } -wasm-bindgen-backend = { version = "=0.2.41", path = "../backend" } +wasm-bindgen-backend = { version = "=0.2.42", path = "../backend" } weedle = "0.8" diff --git a/examples/add/Cargo.toml b/examples/add/Cargo.toml index 563315b2..f435ba79 100644 --- a/examples/add/Cargo.toml +++ b/examples/add/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/canvas/Cargo.toml b/examples/canvas/Cargo.toml index d3696c03..113355a1 100644 --- a/examples/canvas/Cargo.toml +++ b/examples/canvas/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.18" -wasm-bindgen = "0.2.41" +js-sys = "0.3.19" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/char/Cargo.toml b/examples/char/Cargo.toml index 4ceaeab4..16e67ee7 100644 --- a/examples/char/Cargo.toml +++ b/examples/char/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/closures/Cargo.toml b/examples/closures/Cargo.toml index ddf82731..d68043aa 100644 --- a/examples/closures/Cargo.toml +++ b/examples/closures/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" -js-sys = "0.3.18" +wasm-bindgen = "0.2.42" +js-sys = "0.3.19" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/console_log/Cargo.toml b/examples/console_log/Cargo.toml index cb34ae5a..d0645982 100644 --- a/examples/console_log/Cargo.toml +++ b/examples/console_log/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" -web-sys = { version = "0.3.18", features = ['console'] } +wasm-bindgen = "0.2.42" +web-sys = { version = "0.3.19", features = ['console'] } diff --git a/examples/dom/Cargo.toml b/examples/dom/Cargo.toml index 07728839..a9f57cd3 100644 --- a/examples/dom/Cargo.toml +++ b/examples/dom/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/duck-typed-interfaces/Cargo.toml b/examples/duck-typed-interfaces/Cargo.toml index fcccf0e5..ac9352f4 100644 --- a/examples/duck-typed-interfaces/Cargo.toml +++ b/examples/duck-typed-interfaces/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/fetch/Cargo.toml b/examples/fetch/Cargo.toml index f49e08a3..b71c02b5 100644 --- a/examples/fetch/Cargo.toml +++ b/examples/fetch/Cargo.toml @@ -9,9 +9,9 @@ crate-type = ["cdylib"] [dependencies] futures = "0.1.20" -wasm-bindgen = { version = "0.2.41", features = ["serde-serialize"] } -js-sys = "0.3.18" -wasm-bindgen-futures = "0.3.18" +wasm-bindgen = { version = "0.2.42", features = ["serde-serialize"] } +js-sys = "0.3.19" +wasm-bindgen-futures = "0.3.19" serde = { version = "1.0.80", features = ["derive"] } serde_derive = "^1.0.59" diff --git a/examples/guide-supported-types-examples/Cargo.toml b/examples/guide-supported-types-examples/Cargo.toml index 3cf9253a..cd4f79d9 100644 --- a/examples/guide-supported-types-examples/Cargo.toml +++ b/examples/guide-supported-types-examples/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/hello_world/Cargo.toml b/examples/hello_world/Cargo.toml index 99046b37..e0de5b6f 100644 --- a/examples/hello_world/Cargo.toml +++ b/examples/hello_world/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/import_js/crate/Cargo.toml b/examples/import_js/crate/Cargo.toml index 1d2ce7dc..033270d1 100644 --- a/examples/import_js/crate/Cargo.toml +++ b/examples/import_js/crate/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/julia_set/Cargo.toml b/examples/julia_set/Cargo.toml index 850d3d80..e6cc0955 100644 --- a/examples/julia_set/Cargo.toml +++ b/examples/julia_set/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/paint/Cargo.toml b/examples/paint/Cargo.toml index 94faaa8f..c0c3b8b9 100644 --- a/examples/paint/Cargo.toml +++ b/examples/paint/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.18" -wasm-bindgen = "0.2.41" +js-sys = "0.3.19" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/performance/Cargo.toml b/examples/performance/Cargo.toml index 117a537b..144f1837 100644 --- a/examples/performance/Cargo.toml +++ b/examples/performance/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" humantime = "1" [dependencies.web-sys] diff --git a/examples/raytrace-parallel/Cargo.toml b/examples/raytrace-parallel/Cargo.toml index 37687bfc..481ef4bc 100644 --- a/examples/raytrace-parallel/Cargo.toml +++ b/examples/raytrace-parallel/Cargo.toml @@ -10,10 +10,10 @@ crate-type = ["cdylib"] [dependencies] console_error_panic_hook = "0.1" futures = "0.1" -js-sys = "0.3.18" +js-sys = "0.3.19" raytracer = { git = 'https://github.com/alexcrichton/raytracer', branch = 'update-deps' } -wasm-bindgen = { version = "0.2.41", features = ['serde-serialize'] } -wasm-bindgen-futures = "0.3.18" +wasm-bindgen = { version = "0.2.42", features = ['serde-serialize'] } +wasm-bindgen-futures = "0.3.19" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/request-animation-frame/Cargo.toml b/examples/request-animation-frame/Cargo.toml index 36a965d3..515266b0 100644 --- a/examples/request-animation-frame/Cargo.toml +++ b/examples/request-animation-frame/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/todomvc/Cargo.toml b/examples/todomvc/Cargo.toml index 760fb862..32e8c566 100644 --- a/examples/todomvc/Cargo.toml +++ b/examples/todomvc/Cargo.toml @@ -11,8 +11,8 @@ crate-type = ["cdylib"] askama = "0.7.2" [dependencies] -js-sys = "0.3.18" -wasm-bindgen = "0.2.41" +js-sys = "0.3.19" +wasm-bindgen = "0.2.42" askama = "0.7.2" console_error_panic_hook = "0.1.5" diff --git a/examples/wasm-in-wasm/Cargo.toml b/examples/wasm-in-wasm/Cargo.toml index 80ed879c..88b2e0d6 100644 --- a/examples/wasm-in-wasm/Cargo.toml +++ b/examples/wasm-in-wasm/Cargo.toml @@ -8,5 +8,5 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" -js-sys = "0.3.18" +wasm-bindgen = "0.2.42" +js-sys = "0.3.19" diff --git a/examples/wasm2js/Cargo.toml b/examples/wasm2js/Cargo.toml index 1dc3a27f..8cb6d32d 100644 --- a/examples/wasm2js/Cargo.toml +++ b/examples/wasm2js/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" diff --git a/examples/webaudio/Cargo.toml b/examples/webaudio/Cargo.toml index 3950e4d1..9eb94ba7 100644 --- a/examples/webaudio/Cargo.toml +++ b/examples/webaudio/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/webgl/Cargo.toml b/examples/webgl/Cargo.toml index 71c632c9..de49b258 100644 --- a/examples/webgl/Cargo.toml +++ b/examples/webgl/Cargo.toml @@ -8,8 +8,8 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -js-sys = "0.3.18" -wasm-bindgen = "0.2.41" +js-sys = "0.3.19" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" diff --git a/examples/without-a-bundler/Cargo.toml b/examples/without-a-bundler/Cargo.toml index 9bc3e181..3d009239 100644 --- a/examples/without-a-bundler/Cargo.toml +++ b/examples/without-a-bundler/Cargo.toml @@ -8,7 +8,7 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -wasm-bindgen = "0.2.41" +wasm-bindgen = "0.2.42" [dependencies.web-sys] version = "0.3.4" From ba88ae8b640820344e9e9097619ef9f23daefa78 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Apr 2019 13:04:21 -0700 Subject: [PATCH 15/23] Improve Boolean/Number/JsString consistency * Ensure `PartialEq` is implemented from these types to native Rust types * Implement `From` between these type and native Rust types * Deprecated `Number::new` and `Boolean::new` to discourage use of the object forms, recommending the `from` constructors instead. Closes #1446 --- crates/js-sys/src/lib.rs | 67 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index c96b6ae0..e62930ee 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -467,13 +467,14 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone)] pub type Boolean; /// The `Boolean()` constructor creates an object wrapper for a boolean value. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) #[wasm_bindgen(constructor)] + #[deprecated(note = "recommended to use `Boolean::from` instead")] pub fn new(value: &JsValue) -> Boolean; /// The `valueOf()` method returns the primitive value of a `Boolean` object. @@ -483,6 +484,35 @@ extern "C" { pub fn value_of(this: &Boolean) -> bool; } +impl From for Boolean { + #[inline] + fn from(b: bool) -> Boolean { + Boolean::unchecked_from_js(JsValue::from(b)) + } +} + +impl From for bool { + #[inline] + fn from(b: Boolean) -> bool { + b.value_of() + } +} + +impl PartialEq for Boolean { + #[inline] + fn eq(&self, other: &bool) -> bool { + self.value_of() == *other + } +} + +impl Eq for Boolean {} + +impl fmt::Debug for Boolean { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.value_of().fmt(f) + } +} + // DataView #[wasm_bindgen] extern "C" { @@ -1406,7 +1436,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone)] pub type Number; /// The Number.isFinite() method determines whether the passed value is a finite number. @@ -1441,6 +1471,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) #[wasm_bindgen(constructor)] + #[deprecated(note = "recommended to use `Number::from` instead")] pub fn new(value: &JsValue) -> Number; /// The Number.parseInt() method parses a string argument and returns an @@ -1500,6 +1531,38 @@ extern "C" { pub fn value_of(this: &Number) -> f64; } +macro_rules! number_from { + ($($x:ident)*) => ($( + impl From<$x> for Number { + #[inline] + fn from(x: $x) -> Number { + Number::unchecked_from_js(JsValue::from(x)) + } + } + + impl PartialEq<$x> for Number { + #[inline] + fn eq(&self, other: &$x) -> bool { + self.value_of() == f64::from(*other) + } + } + )*) +} +number_from!(i8 u8 i16 u16 i32 u32 f32 f64); + +impl From for f64 { + #[inline] + fn from(n: Number) -> f64 { + n.value_of() + } +} + +impl fmt::Debug for Number { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.value_of().fmt(f) + } +} + // Date. #[wasm_bindgen] extern "C" { From 018b9b4e091e168b7254bbbaeb453c2de4520a3e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Apr 2019 08:54:05 -0700 Subject: [PATCH 16/23] Fix compile of js-sys --- crates/js-sys/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index e62930ee..dec02809 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -467,7 +467,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone)] + #[derive(Clone, PartialEq)] pub type Boolean; /// The `Boolean()` constructor creates an object wrapper for a boolean value. From e39404e6332748d99e9b17674fd1cc1f4894c9e7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Apr 2019 08:56:36 -0700 Subject: [PATCH 17/23] Add support for isize/usize arrays Closes #1426 --- src/convert/slices.rs | 2 +- tests/wasm/slice.js | 12 ++++++++++++ tests/wasm/slice.rs | 8 ++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/convert/slices.rs b/src/convert/slices.rs index d99fbbbf..a3cb6ec9 100644 --- a/src/convert/slices.rs +++ b/src/convert/slices.rs @@ -123,7 +123,7 @@ macro_rules! vectors { } vectors! { - u8 i8 u16 i16 u32 i32 u64 i64 f32 f64 + u8 i8 u16 i16 u32 i32 u64 i64 usize isize f32 f64 } if_std! { diff --git a/tests/wasm/slice.js b/tests/wasm/slice.js index 7ec7ee8f..373e3859 100644 --- a/tests/wasm/slice.js +++ b/tests/wasm/slice.js @@ -24,10 +24,12 @@ exports.js_export = () => { i32[0] = 1; i32[1] = 2; assert.deepStrictEqual(wasm.export_i32(i32), i32); + assert.deepStrictEqual(wasm.export_isize(i32), i32); const u32 = new Uint32Array(2); u32[0] = 1; u32[1] = 2; assert.deepStrictEqual(wasm.export_u32(u32), u32); + assert.deepStrictEqual(wasm.export_usize(u32), u32); const f32 = new Float32Array(2); f32[0] = 1; @@ -73,6 +75,7 @@ exports.import_js_i32 = a => { assert.strictEqual(a[1], 2); return a; }; +exports.import_js_isize = exports.import_js_i32; exports.import_js_u32 = a => { assert.strictEqual(a.length, 2); @@ -80,6 +83,7 @@ exports.import_js_u32 = a => { assert.strictEqual(a[1], 2); return a; }; +exports.import_js_usize = exports.import_js_u32; exports.import_js_f32 = a => { assert.strictEqual(a.length, 2); @@ -118,10 +122,12 @@ exports.js_import = () => { i32[0] = 1; i32[1] = 2; assert.deepStrictEqual(wasm.import_rust_i32(i32), i32); + assert.deepStrictEqual(wasm.import_rust_isize(i32), i32); const u32 = new Uint32Array(2); u32[0] = 1; u32[1] = 2; assert.deepStrictEqual(wasm.import_rust_u32(u32), u32); + assert.deepStrictEqual(wasm.import_rust_usize(u32), u32); const f32 = new Float32Array(2); f32[0] = 1; @@ -140,6 +146,8 @@ exports.js_pass_array = () => { wasm.pass_array_rust_u16([1, 2]); wasm.pass_array_rust_i32([1, 2]); wasm.pass_array_rust_u32([1, 2]); + wasm.pass_array_rust_isize([1, 2]); + wasm.pass_array_rust_usize([1, 2]); wasm.pass_array_rust_f32([1, 2]); wasm.pass_array_rust_f64([1, 2]); }; @@ -158,6 +166,8 @@ exports.import_mut_js_i16 = import_mut_foo; exports.import_mut_js_u16 = import_mut_foo; exports.import_mut_js_i32 = import_mut_foo; exports.import_mut_js_u32 = import_mut_foo; +exports.import_mut_js_isize = import_mut_foo; +exports.import_mut_js_usize = import_mut_foo; exports.import_mut_js_f32 = import_mut_foo; exports.import_mut_js_f64 = import_mut_foo; @@ -182,6 +192,8 @@ exports.js_export_mut = () => { export_mut_run(new Uint16Array(3), wasm.export_mut_u16); export_mut_run(new Int32Array(3), wasm.export_mut_i32); export_mut_run(new Uint32Array(3), wasm.export_mut_u32); + export_mut_run(new Int32Array(3), wasm.export_mut_isize); + export_mut_run(new Uint32Array(3), wasm.export_mut_usize); export_mut_run(new Float32Array(3), wasm.export_mut_f32); export_mut_run(new Float64Array(3), wasm.export_mut_f64); }; diff --git a/tests/wasm/slice.rs b/tests/wasm/slice.rs index e14ed187..8e299c0f 100644 --- a/tests/wasm/slice.rs +++ b/tests/wasm/slice.rs @@ -40,6 +40,8 @@ export_macro! { (u16, export_u16) (i32, export_i32) (u32, export_u32) + (isize, export_isize) + (usize, export_usize) (f32, export_f32) (f64, export_f64) } @@ -73,6 +75,8 @@ import_macro! { (import_rust_u16, import_js_u16, u16) (import_rust_i32, import_js_i32, i32) (import_rust_u32, import_js_u32, u32) + (import_rust_isize, import_js_isize, isize) + (import_rust_usize, import_js_usize, usize) (import_rust_f32, import_js_f32, f32) (import_rust_f64, import_js_f64, f64) } @@ -100,6 +104,8 @@ pass_array_marco! { (pass_array_rust_u16, u16) (pass_array_rust_i32, i32) (pass_array_rust_u32, u32) + (pass_array_rust_isize, isize) + (pass_array_rust_usize, usize) (pass_array_rust_f32, f32) (pass_array_rust_f64, f64) } @@ -169,6 +175,8 @@ export_mut_macro! { (u16, export_mut_u16) (i32, export_mut_i32) (u32, export_mut_u32) + (isize, export_mut_isize) + (usize, export_mut_usize) (f32, export_mut_f32) (f64, export_mut_f64) } From df8da56a6cad5bf09f9833058ce49176b3626d08 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Apr 2019 08:22:42 -0700 Subject: [PATCH 18/23] Add PartialEq/Eq to many `js-sys` types This commit adds `#[derive(PartialEq, Eq)]` to many types throughout `js-sys`. These types are basically all based on `Object`, which means that `Object.is` can be used for `PartialEq` and the `Eq` requirements are upheld. The macro has also been updated to internally store the deref target instead of unconditionally storing `JsValue`, allowing `#[derive]` to work a bit better in these situations. --- crates/backend/src/codegen.rs | 49 +++++++++++----------- crates/js-sys/src/lib.rs | 78 +++++++++++++++++++---------------- 2 files changed, 68 insertions(+), 59 deletions(-) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index e3788a2c..b1ac809a 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -578,6 +578,16 @@ impl ToTokens for ast::ImportType { let const_name = format!("__wbg_generated_const_{}", rust_name); let const_name = Ident::new(&const_name, Span::call_site()); let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site()); + + let internal_obj = match self.extends.first() { + Some(target) => { + quote! { #target } + } + None => { + quote! { wasm_bindgen::JsValue } + } + }; + (quote! { #[allow(bad_style)] #(#attrs)* @@ -585,7 +595,7 @@ impl ToTokens for ast::ImportType { #[repr(transparent)] #[allow(clippy::all)] #vis struct #rust_name { - obj: wasm_bindgen::JsValue, + obj: #internal_obj } #[allow(bad_style)] @@ -604,6 +614,15 @@ impl ToTokens for ast::ImportType { } } + impl core::ops::Deref for #rust_name { + type Target = #internal_obj; + + #[inline] + fn deref(&self) -> &#internal_obj { + &self.obj + } + } + impl IntoWasmAbi for #rust_name { type Abi = ::Abi; @@ -629,7 +648,7 @@ impl ToTokens for ast::ImportType { #[inline] unsafe fn from_abi(js: Self::Abi, extra: &mut Stack) -> Self { #rust_name { - obj: JsValue::from_abi(js, extra), + obj: JsValue::from_abi(js, extra).into(), } } } @@ -656,7 +675,7 @@ impl ToTokens for ast::ImportType { unsafe fn ref_from_abi(js: Self::Abi, extra: &mut Stack) -> Self::Anchor { let tmp = ::ref_from_abi(js, extra); core::mem::ManuallyDrop::new(#rust_name { - obj: core::mem::ManuallyDrop::into_inner(tmp), + obj: core::mem::ManuallyDrop::into_inner(tmp).into(), }) } } @@ -665,20 +684,20 @@ impl ToTokens for ast::ImportType { impl From for #rust_name { #[inline] fn from(obj: JsValue) -> #rust_name { - #rust_name { obj } + #rust_name { obj: obj.into() } } } impl AsRef for #rust_name { #[inline] - fn as_ref(&self) -> &JsValue { &self.obj } + fn as_ref(&self) -> &JsValue { self.obj.as_ref() } } impl From<#rust_name> for JsValue { #[inline] fn from(obj: #rust_name) -> JsValue { - obj.obj + obj.obj.into() } } @@ -703,7 +722,7 @@ impl ToTokens for ast::ImportType { #[inline] fn unchecked_from_js(val: JsValue) -> Self { - #rust_name { obj: val } + #rust_name { obj: val.into() } } #[inline] @@ -719,22 +738,6 @@ impl ToTokens for ast::ImportType { }) .to_tokens(tokens); - let deref_target = match self.extends.first() { - Some(target) => quote! { #target }, - None => quote! { JsValue }, - }; - (quote! { - #[allow(clippy::all)] - impl core::ops::Deref for #rust_name { - type Target = #deref_target; - - #[inline] - fn deref(&self) -> &#deref_target { - self.as_ref() - } - } - }) - .to_tokens(tokens); for superclass in self.extends.iter() { (quote! { #[allow(clippy::all)] diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index dec02809..b97c7500 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -127,7 +127,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Array; /// Creates a new empty array @@ -392,7 +392,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type ArrayBuffer; /// The `ArrayBuffer` object is used to represent a generic, @@ -467,7 +467,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, PartialEq)] + #[derive(Clone, PartialEq, Eq)] pub type Boolean; /// The `Boolean()` constructor creates an object wrapper for a boolean value. @@ -505,8 +505,6 @@ impl PartialEq for Boolean { } } -impl Eq for Boolean {} - impl fmt::Debug for Boolean { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.value_of().fmt(f) @@ -517,7 +515,7 @@ impl fmt::Debug for Boolean { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type DataView; /// The `DataView` view provides a low-level interface for reading and @@ -749,7 +747,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Error; /// The Error constructor creates an error object. @@ -788,7 +786,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object, extends = Error)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type EvalError; /// The EvalError object indicates an error regarding the global eval() function. This @@ -804,7 +802,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Function; /// The `Function` constructor creates a new `Function` object. Calling the @@ -911,7 +909,7 @@ impl Function { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Generator; /// The next() method returns an object with two properties done and value. @@ -939,7 +937,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Map; /// The clear() method removes all elements from a Map object. @@ -1165,7 +1163,8 @@ extern "C" { /// The result of calling `next()` on a JS iterator. /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) - #[derive(Clone, Debug)] + #[wasm_bindgen(extends = Object)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type IteratorNext; /// Has the value `true` if the iterator is past the end of the iterated @@ -1187,8 +1186,8 @@ extern "C" { // Math #[wasm_bindgen] extern "C" { - #[derive(Clone, Debug)] #[wasm_bindgen(extends = Object)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Math; /// The Math.abs() function returns the absolute value of a number, that is @@ -1567,7 +1566,7 @@ impl fmt::Debug for Number { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Date; /// The getDate() method returns the day of the month for the @@ -2161,6 +2160,15 @@ impl Object { } } +impl PartialEq for Object { + #[inline] + fn eq(&self, other: &Object) -> bool { + Object::is(self.as_ref(), other.as_ref()) + } +} + +impl Eq for Object {} + // Proxy #[wasm_bindgen] extern "C" { @@ -2191,7 +2199,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError) #[wasm_bindgen(extends = Error, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type RangeError; /// The RangeError object indicates an error when a value is not in the set @@ -2210,7 +2218,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError) #[wasm_bindgen(extends = Error, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type ReferenceError; /// The ReferenceError object represents an error when a non-existent @@ -2224,8 +2232,8 @@ extern "C" { // Reflect #[wasm_bindgen] extern "C" { - #[derive(Clone, Debug)] #[wasm_bindgen(extends = Object)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Reflect; /// The static `Reflect.apply()` method calls a target function with @@ -2384,7 +2392,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type RegExp; /// The exec() method executes a search for a match in a specified @@ -2561,7 +2569,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Set; /// The `add()` method appends a new element with a specified value to the @@ -2651,7 +2659,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError) #[wasm_bindgen(extends = Error, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type SyntaxError; /// A SyntaxError is thrown when the JavaScript engine encounters tokens or @@ -2671,7 +2679,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) #[wasm_bindgen(extends = Error, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type TypeError; /// The TypeError object represents an error when a value is not of the @@ -2690,7 +2698,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError) #[wasm_bindgen(extends = Error, extends = Object, js_name = URIError)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type UriError; /// The URIError object represents an error when a global URI handling @@ -2705,7 +2713,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type WeakMap; /// The [`WeakMap`] object is a collection of key/value pairs in which the @@ -2749,7 +2757,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type WeakSet; /// The `WeakSet` object lets you store weakly held objects in a collection. @@ -2836,7 +2844,7 @@ pub mod WebAssembly { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/CompileError) #[wasm_bindgen(extends = Error, js_namespace = WebAssembly)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type CompileError; /// The `WebAssembly.CompileError()` constructor creates a new @@ -2858,7 +2866,7 @@ pub mod WebAssembly { /// /// [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)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Instance; /// The `WebAssembly.Instance()` constructor function can be called to @@ -2889,7 +2897,7 @@ pub mod WebAssembly { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError) #[wasm_bindgen(extends = Error, js_namespace = WebAssembly)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type LinkError; /// The `WebAssembly.LinkError()` constructor creates a new WebAssembly @@ -2910,7 +2918,7 @@ pub mod WebAssembly { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/RuntimeError) #[wasm_bindgen(extends = Error, js_namespace = WebAssembly)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type RuntimeError; /// The `WebAssembly.RuntimeError()` constructor creates a new WebAssembly @@ -2931,7 +2939,7 @@ pub mod WebAssembly { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Module) #[wasm_bindgen(js_namespace = WebAssembly, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Module; /// A `WebAssembly.Module` object contains stateless WebAssembly code @@ -2973,7 +2981,7 @@ pub mod WebAssembly { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table) #[wasm_bindgen(js_namespace = WebAssembly, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Table; /// The `WebAssembly.Table()` constructor creates a new `Table` object @@ -3019,7 +3027,7 @@ pub mod WebAssembly { extern "C" { /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory) #[wasm_bindgen(js_namespace = WebAssembly, extends = Object)] - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type Memory; /// The `WebAssembly.Memory()` constructor creates a new `Memory` object @@ -3060,8 +3068,8 @@ extern "C" { /// 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)] + #[derive(Clone, Debug, PartialEq, Eq)] pub type JSON; /// The `JSON.parse()` method parses a JSON string, constructing the @@ -3120,7 +3128,7 @@ extern "C" { #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_name = String, extends = Object)] - #[derive(Clone)] + #[derive(Clone, PartialEq, Eq)] pub type JsString; /// The length property of a String object indicates the length of a string, @@ -3644,9 +3652,7 @@ impl<'a> PartialEq<&'a String> for JsString { impl<'a> From<&'a str> for JsString { fn from(s: &'a str) -> Self { - JsString { - obj: JsValue::from_str(s), - } + JsString::unchecked_from_js(JsValue::from_str(s)) } } From ba1f67d854b1d1ec2613d49ad00ab6c5a823f1fb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Apr 2019 09:02:39 -0700 Subject: [PATCH 19/23] Remove some unnecessary `unsafe` in `js-sys` --- crates/js-sys/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index b97c7500..d53e9d00 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -898,7 +898,7 @@ impl Function { /// `None`. pub fn try_from(val: &JsValue) -> Option<&Function> { if val.is_function() { - Some(unsafe { mem::transmute(val) }) + Some(val.unchecked_ref()) } else { None } @@ -2153,7 +2153,7 @@ impl Object { /// `None`. pub fn try_from(val: &JsValue) -> Option<&Object> { if val.is_object() { - Some(unsafe { mem::transmute(val) }) + Some(val.unchecked_ref()) } else { None } @@ -3588,7 +3588,7 @@ impl JsString { /// `None`. pub fn try_from(val: &JsValue) -> Option<&JsString> { if val.is_string() { - Some(unsafe { mem::transmute(val) }) + Some(val.unchecked_ref()) } else { None } From cb880bdbff99ad1038a47bbc8b62f6df4335073c Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Tue, 26 Mar 2019 19:29:46 +0000 Subject: [PATCH 20/23] Add customisable `is_type_of` --- crates/backend/src/ast.rs | 1 + crates/backend/src/codegen.rs | 9 +++++++++ crates/js-sys/src/lib.rs | 28 ++++++++++++---------------- crates/macro-support/src/parser.rs | 8 ++++++++ crates/webidl/src/lib.rs | 1 + src/cast.rs | 16 ++++++++++++---- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index e61f5878..aeb56ccb 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -183,6 +183,7 @@ pub struct ImportType { pub attrs: Vec, pub doc_comment: Option, pub instanceof_shim: String, + pub is_type_of: Option, pub extends: Vec, pub vendor_prefixes: Vec, } diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index b1ac809a..6ad6a873 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -588,6 +588,13 @@ impl ToTokens for ast::ImportType { } }; + let is_type_of = self.is_type_of.as_ref().map(|is_type_of| quote! { + fn is_type_of(val: &JsValue) -> bool { + let is_type_of: fn(&JsValue) -> bool = #is_type_of; + is_type_of(val) + } + }); + (quote! { #[allow(bad_style)] #(#attrs)* @@ -720,6 +727,8 @@ impl ToTokens for ast::ImportType { panic!("cannot check instanceof on non-wasm targets"); } + #is_type_of + #[inline] fn unchecked_from_js(val: JsValue) -> Self { #rust_name { obj: val.into() } diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index d53e9d00..12f8e270 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -126,7 +126,7 @@ extern "C" { // Array #[wasm_bindgen] extern "C" { - #[wasm_bindgen(extends = Object)] + #[wasm_bindgen(extends = Object, is_type_of = Array::is_array)] #[derive(Clone, Debug, PartialEq, Eq)] pub type Array; @@ -466,7 +466,7 @@ extern "C" { // Boolean #[wasm_bindgen] extern "C" { - #[wasm_bindgen(extends = Object)] + #[wasm_bindgen(extends = Object, is_type_of = |v| v.as_bool().is_some())] #[derive(Clone, PartialEq, Eq)] pub type Boolean; @@ -801,7 +801,7 @@ extern "C" { // Function #[wasm_bindgen] extern "C" { - #[wasm_bindgen(extends = Object)] + #[wasm_bindgen(extends = Object, is_type_of = JsValue::is_function)] #[derive(Clone, Debug, PartialEq, Eq)] pub type Function; @@ -897,11 +897,7 @@ impl Function { /// If this JS value is not an instance of a function then this returns /// `None`. pub fn try_from(val: &JsValue) -> Option<&Function> { - if val.is_function() { - Some(val.unchecked_ref()) - } else { - None - } + val.dyn_ref() } } @@ -1141,7 +1137,10 @@ pub fn try_iter(val: &JsValue) -> Result, JsValue> { return Ok(None); } - let iter_fn: Function = iter_fn.unchecked_into(); + let iter_fn: Function = match iter_fn.dyn_into() { + Ok(iter_fn) => iter_fn, + Err(_) => return Ok(None) + }; let it = iter_fn.call0(val)?; if !it.is_object() { return Ok(None); @@ -1434,7 +1433,7 @@ extern "C" { // Number. #[wasm_bindgen] extern "C" { - #[wasm_bindgen(extends = Object)] + #[wasm_bindgen(extends = Object, is_type_of = |v| v.as_f64().is_some())] #[derive(Clone)] pub type Number; @@ -3127,7 +3126,7 @@ extern "C" { // JsString #[wasm_bindgen] extern "C" { - #[wasm_bindgen(js_name = String, extends = Object)] + #[wasm_bindgen(js_name = String, extends = Object, is_type_of = JsValue::is_string)] #[derive(Clone, PartialEq, Eq)] pub type JsString; @@ -3587,11 +3586,7 @@ impl JsString { /// If this JS value is not an instance of a string then this returns /// `None`. pub fn try_from(val: &JsValue) -> Option<&JsString> { - if val.is_string() { - Some(val.unchecked_ref()) - } else { - None - } + val.dyn_ref() } /// Returns whether this string is a valid UTF-16 string. @@ -3683,6 +3678,7 @@ impl fmt::Debug for JsString { // Symbol #[wasm_bindgen] extern "C" { + #[wasm_bindgen(is_type_of = JsValue::is_symbol)] #[derive(Clone, Debug)] pub type Symbol; diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 6ad5172e..1ac67cde 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -45,6 +45,7 @@ macro_rules! attrgen { (readonly, Readonly(Span)), (js_name, JsName(Span, String, Span)), (js_class, JsClass(Span, String, Span)), + (is_type_of, IsTypeOf(Span, syn::Expr)), (extends, Extends(Span, syn::Path)), (vendor_prefix, VendorPrefix(Span, Ident)), (variadic, Variadic(Span)), @@ -240,6 +241,11 @@ impl Parse for BindgenAttr { return Ok(BindgenAttr::$variant(attr_span, input.parse()?)); }); + (@parser $variant:ident(Span, syn::Expr)) => ({ + input.parse::()?; + return Ok(BindgenAttr::$variant(attr_span, input.parse()?)); + }); + (@parser $variant:ident(Span, String, Span)) => ({ input.parse::()?; let (val, span) = match input.parse::() { @@ -515,6 +521,7 @@ impl ConvertToAst for syn::ForeignItemType { .js_name() .map(|s| s.0) .map_or_else(|| self.ident.to_string(), |s| s.to_string()); + let is_type_of = attrs.is_type_of().cloned(); let shim = format!("__wbg_instanceof_{}_{}", self.ident, ShortHash(&self.ident)); let mut extends = Vec::new(); let mut vendor_prefixes = Vec::new(); @@ -537,6 +544,7 @@ impl ConvertToAst for syn::ForeignItemType { attrs: self.attrs, doc_comment: None, instanceof_shim: shim, + is_type_of, rust_name: self.ident, js_name, extends, diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index cdd86a58..08a85397 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -514,6 +514,7 @@ impl<'src> FirstPassRecord<'src> { attrs, doc_comment: None, instanceof_shim: format!("__widl_instanceof_{}", name), + is_type_of: None, extends: Vec::new(), vendor_prefixes: Vec::new(), }; diff --git a/src/cast.rs b/src/cast.rs index fa690e3d..fd78a9a9 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -30,14 +30,14 @@ where /// Performs a dynamic cast (checked at runtime) of this value into the /// target type `T`. /// - /// This method will return `Err(self)` if `self.is_instance_of::()` + /// This method will return `Err(self)` if `T::is_type_of(self)` /// returns `false`, and otherwise it will return `Ok(T)` manufactured with /// an unchecked cast (verified correct via the `instanceof` operation). fn dyn_into(self) -> Result where T: JsCast, { - if self.is_instance_of::() { + if T::is_type_of(self.as_ref()) { Ok(self.unchecked_into()) } else { Err(self) @@ -47,14 +47,14 @@ where /// Performs a dynamic cast (checked at runtime) of this value into the /// target type `T`. /// - /// This method will return `None` if `self.is_instance_of::()` + /// This method will return `None` if `T::is_type_of(self)` /// returns `false`, and otherwise it will return `Some(&T)` manufactured /// with an unchecked cast (verified correct via the `instanceof` operation). fn dyn_ref(&self) -> Option<&T> where T: JsCast, { - if self.is_instance_of::() { + if T::is_type_of(self.as_ref()) { Some(self.unchecked_ref()) } else { None @@ -100,6 +100,14 @@ where /// won't need to call this. fn instanceof(val: &JsValue) -> bool; + /// Performs a dynamic check to see whether the `JsValue` provided + /// is a value of this type. + /// + /// Unlike `instanceof`, this can be specialised to use a custom check. + fn is_type_of(val: &JsValue) -> bool { + Self::instanceof(val) + } + /// Performs a zero-cost unchecked conversion from a `JsValue` into an /// instance of `Self` /// From c77b46af7d393ab2577f7c0e59169197d62411c1 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Fri, 12 Apr 2019 17:41:51 +0100 Subject: [PATCH 21/23] Add `has_type` and update `is_instance_of` docs --- src/cast.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/cast.rs b/src/cast.rs index fd78a9a9..6db649cb 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -20,6 +20,9 @@ where /// /// This method performs a dynamic check (at runtime) using the JS /// `instanceof` operator. This method returns `self instanceof T`. + /// + /// Note that `instanceof` does not work with primitive values or across + /// different realms (e.g. iframes). Prefer using `has_type` instead. fn is_instance_of(&self) -> bool where T: JsCast, @@ -27,17 +30,28 @@ where T::instanceof(self.as_ref()) } + /// Test whether this JS value has a type `T`. + /// + /// Unlike `is_instance_of`, the type can override this to a specialised + /// check that works reliably with primitives and across realms. + fn has_type(&self) -> bool + where + T: JsCast, + { + T::is_type_of(self.as_ref()) + } + /// Performs a dynamic cast (checked at runtime) of this value into the /// target type `T`. /// - /// This method will return `Err(self)` if `T::is_type_of(self)` + /// This method will return `Err(self)` if `self.has_type::()` /// returns `false`, and otherwise it will return `Ok(T)` manufactured with /// an unchecked cast (verified correct via the `instanceof` operation). fn dyn_into(self) -> Result where T: JsCast, { - if T::is_type_of(self.as_ref()) { + if self.has_type::() { Ok(self.unchecked_into()) } else { Err(self) @@ -47,14 +61,14 @@ where /// Performs a dynamic cast (checked at runtime) of this value into the /// target type `T`. /// - /// This method will return `None` if `T::is_type_of(self)` + /// This method will return `None` if `self.has_type::()` /// returns `false`, and otherwise it will return `Some(&T)` manufactured /// with an unchecked cast (verified correct via the `instanceof` operation). fn dyn_ref(&self) -> Option<&T> where T: JsCast, { - if T::is_type_of(self.as_ref()) { + if self.has_type::() { Some(self.unchecked_ref()) } else { None @@ -103,7 +117,12 @@ where /// Performs a dynamic check to see whether the `JsValue` provided /// is a value of this type. /// - /// Unlike `instanceof`, this can be specialised to use a custom check. + /// Unlike `instanceof`, this can be specialised to use a custom check by + /// adding a `#[wasm_bindgen(is_type_of = callback)]` attribute to the + /// type import declaration. + /// + /// Other than that, this is intended to be an internal implementation + /// detail of `has_type` and you likely won't need to call this. fn is_type_of(val: &JsValue) -> bool { Self::instanceof(val) } From c4776becbb9f7aa01d27a5e014ec14adaed462d7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Apr 2019 10:54:36 -0700 Subject: [PATCH 22/23] Touch up descriptions of `has_type` --- crates/backend/src/codegen.rs | 1 + src/cast.rs | 48 +++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 6ad6a873..310c5847 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -589,6 +589,7 @@ impl ToTokens for ast::ImportType { }; let is_type_of = self.is_type_of.as_ref().map(|is_type_of| quote! { + #[inline] fn is_type_of(val: &JsValue) -> bool { let is_type_of: fn(&JsValue) -> bool = #is_type_of; is_type_of(val) diff --git a/src/cast.rs b/src/cast.rs index 6db649cb..f8f0694f 100644 --- a/src/cast.rs +++ b/src/cast.rs @@ -16,24 +16,17 @@ pub trait JsCast where Self: AsRef + Into, { - /// Test whether this JS value is an instance of the type `T`. - /// - /// This method performs a dynamic check (at runtime) using the JS - /// `instanceof` operator. This method returns `self instanceof T`. - /// - /// Note that `instanceof` does not work with primitive values or across - /// different realms (e.g. iframes). Prefer using `has_type` instead. - fn is_instance_of(&self) -> bool - where - T: JsCast, - { - T::instanceof(self.as_ref()) - } - /// Test whether this JS value has a type `T`. /// - /// Unlike `is_instance_of`, the type can override this to a specialised - /// check that works reliably with primitives and across realms. + /// This method will dynamically check to see if this JS object can be + /// casted to the JS object of type `T`. Usually this uses the `instanceof` + /// operator. This also works with primitive types like + /// booleans/strings/numbers as well as cross-realm object like `Array` + /// which can originate from other iframes. + /// + /// In general this is intended to be a more robust version of + /// `is_instance_of`, but if you want strictly the `instanceof` operator + /// it's recommended to use that instead. fn has_type(&self) -> bool where T: JsCast, @@ -46,7 +39,7 @@ where /// /// This method will return `Err(self)` if `self.has_type::()` /// returns `false`, and otherwise it will return `Ok(T)` manufactured with - /// an unchecked cast (verified correct via the `instanceof` operation). + /// an unchecked cast (verified correct via the `has_type` operation). fn dyn_into(self) -> Result where T: JsCast, @@ -63,7 +56,7 @@ where /// /// This method will return `None` if `self.has_type::()` /// returns `false`, and otherwise it will return `Some(&T)` manufactured - /// with an unchecked cast (verified correct via the `instanceof` operation). + /// with an unchecked cast (verified correct via the `has_type` operation). fn dyn_ref(&self) -> Option<&T> where T: JsCast, @@ -107,11 +100,28 @@ where T::unchecked_from_js_ref(self.as_ref()) } + /// Test whether this JS value is an instance of the type `T`. + /// + /// This method performs a dynamic check (at runtime) using the JS + /// `instanceof` operator. This method returns `self instanceof T`. + /// + /// Note that `instanceof` does not always work with primitive values or + /// across different realms (e.g. iframes). If you're not sure whether you + /// specifically need only `instanceof` it's recommended to use `has_type` + /// instead. + fn is_instance_of(&self) -> bool + where + T: JsCast, + { + T::instanceof(self.as_ref()) + } + /// Performs a dynamic `instanceof` check to see whether the `JsValue` /// provided is an instance of this type. /// /// This is intended to be an internal implementation detail, you likely - /// won't need to call this. + /// won't need to call this. It's generally called through the + /// `is_instance_of` method instead. fn instanceof(val: &JsValue) -> bool; /// Performs a dynamic check to see whether the `JsValue` provided From 2f524ee49425abcc1d421b70d472a245c913d30d Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Fri, 12 Apr 2019 20:30:41 +0100 Subject: [PATCH 23/23] Leverage new `is_type_of` for iterator protocol Treats any object of shape `{ next: function }` as an iterator via new `is_type_of` method. This is consistent with JavaScript iteration protocol which we already respect. Also fixes a minor issue that `is_function` was unnecessarily called twice (once explicitly and once as part of `dyn_into` which now does the same check). --- crates/js-sys/src/lib.rs | 50 ++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 12f8e270..09468ed9 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -1025,6 +1025,7 @@ extern "C" { /// /// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) #[derive(Clone, Debug)] + #[wasm_bindgen(is_type_of = Iterator::looks_like_iterator)] pub type Iterator; /// The next method always has to return an object with appropriate @@ -1035,6 +1036,26 @@ extern "C" { pub fn next(this: &Iterator) -> Result; } +impl Iterator { + fn looks_like_iterator(it: &JsValue) -> bool { + #[wasm_bindgen] + extern "C" { + type MaybeIterator; + + #[wasm_bindgen(method, getter)] + fn next(this: &MaybeIterator) -> JsValue; + } + + if !it.is_object() { + return false; + } + + let it = it.unchecked_ref::(); + + it.next().is_function() + } +} + /// An iterator over the JS `Symbol.iterator` iteration protocol. /// /// Use the `IntoIterator for &js_sys::Iterator` implementation to create this. @@ -1123,37 +1144,20 @@ impl IterState { /// Create an iterator over `val` using the JS iteration protocol and /// `Symbol.iterator`. pub fn try_iter(val: &JsValue) -> Result, JsValue> { - #[wasm_bindgen] - extern "C" { - type MaybeIterator; - - #[wasm_bindgen(method, getter)] - fn next(this: &MaybeIterator) -> JsValue; - } - let iter_sym = Symbol::iterator(); let iter_fn = Reflect::get(val, iter_sym.as_ref())?; - if !iter_fn.is_function() { - return Ok(None); - } let iter_fn: Function = match iter_fn.dyn_into() { Ok(iter_fn) => iter_fn, - Err(_) => return Ok(None) + Err(_) => return Ok(None), }; - let it = iter_fn.call0(val)?; - if !it.is_object() { - return Ok(None); - } - let next = it.unchecked_ref::().next(); + let it: Iterator = match iter_fn.call0(val)?.dyn_into() { + Ok(it) => it, + Err(_) => return Ok(None), + }; - Ok(if next.is_function() { - let it: Iterator = it.unchecked_into(); - Some(it.into_iter()) - } else { - None - }) + Ok(Some(it.into_iter())) } // IteratorNext