Merge branch 'master' into add-wasm-bindgen-skip-attr

This commit is contained in:
alexlapa 2019-04-14 23:43:21 +03:00
commit 00c4dd9b6f
67 changed files with 1030 additions and 214 deletions

View File

@ -32,6 +32,78 @@ 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.
### 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.

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen"
version = "0.2.40"
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.40" }
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.17' }
wasm-bindgen-test = { path = 'crates/test', version = '=0.2.40' }
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' }

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-anyref-xform"
version = "0.2.40"
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"

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-backend"
version = "0.2.40"
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.40" }
wasm-bindgen-shared = { path = "../shared", version = "=0.2.42" }

View File

@ -183,6 +183,7 @@ pub struct ImportType {
pub attrs: Vec<syn::Attribute>,
pub doc_comment: Option<String>,
pub instanceof_shim: String,
pub is_type_of: Option<syn::Expr>,
pub extends: Vec<syn::Path>,
pub vendor_prefixes: Vec<Ident>,
}

View File

@ -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<T: Copy>(){}
assert_copy::<#ty>();
#assert_copy;
let js = js as *mut WasmRefCell<#struct_name>;
assert_not_null(js);
@ -576,6 +578,24 @@ 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 }
}
};
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)
}
});
(quote! {
#[allow(bad_style)]
#(#attrs)*
@ -583,7 +603,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)]
@ -602,6 +622,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 = <JsValue as IntoWasmAbi>::Abi;
@ -627,7 +656,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(),
}
}
}
@ -654,7 +683,7 @@ impl ToTokens for ast::ImportType {
unsafe fn ref_from_abi(js: Self::Abi, extra: &mut Stack) -> Self::Anchor {
let tmp = <JsValue as RefFromWasmAbi>::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(),
})
}
}
@ -663,20 +692,20 @@ impl ToTokens for ast::ImportType {
impl From<JsValue> for #rust_name {
#[inline]
fn from(obj: JsValue) -> #rust_name {
#rust_name { obj }
#rust_name { obj: obj.into() }
}
}
impl AsRef<JsValue> 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()
}
}
@ -699,9 +728,11 @@ 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 }
#rust_name { obj: val.into() }
}
#[inline]
@ -714,24 +745,9 @@ 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)]
@ -1430,3 +1446,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()
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-cli-support"
version = "0.2.40"
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.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.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' }

View File

@ -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
@ -353,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");
}
@ -364,14 +366,22 @@ 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");
}
}
let (init_js, init_ts) = init;
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);
@ -382,7 +392,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 +404,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> {
@ -773,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 {}; }}",
@ -842,7 +860,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<any>}}\n\
*/\n\
export function init \
(module_or_path: RequestInfo | BufferSource | WebAssembly.Module{}): Promise<any>;
",
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,15 +907,21 @@ 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{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 => {{
@ -890,9 +941,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}}) => {{
@ -903,6 +958,7 @@ impl<'a> Context<'a> {
}});
}}
",
init_memory_arg = init_memory_arg,
module = module_name,
init_memory1 = init_memory1,
init_memory2 = init_memory2,
@ -911,7 +967,9 @@ impl<'a> Context<'a> {
} else {
""
},
)
);
(js, ts)
}
fn bind(
@ -1306,13 +1364,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);
ptr = wasm.__wbindgen_realloc(ptr, size, size += arg.length * 3);
}}
WASM_VECTOR_LEN = writeOffset;
return ptr;

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-cli"
version = "0.2.40"
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.40" }
wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" }
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"

View File

@ -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.19"
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.19' }
wasm-bindgen = { path = "../..", version = '0.2.42' }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { path = '../test', version = '0.2.40' }
wasm-bindgen-test = { path = '../test', version = '0.2.42' }

View File

@ -1,6 +1,6 @@
[package]
name = "js-sys"
version = "0.3.17"
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.40" }
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.40' }
wasm-bindgen-futures = { path = '../futures', version = '=0.3.17' }
wasm-bindgen-test = { path = '../test', version = '=0.2.42' }
wasm-bindgen-futures = { path = '../futures', version = '=0.3.19' }

View File

@ -126,8 +126,8 @@ extern "C" {
// Array
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object)]
#[derive(Clone, Debug)]
#[wasm_bindgen(extends = Object, is_type_of = Array::is_array)]
#[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,
@ -466,14 +466,15 @@ extern "C" {
// Boolean
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object)]
#[derive(Clone, Debug)]
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_bool().is_some())]
#[derive(Clone, PartialEq, Eq)]
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,11 +484,38 @@ extern "C" {
pub fn value_of(this: &Boolean) -> bool;
}
impl From<bool> for Boolean {
#[inline]
fn from(b: bool) -> Boolean {
Boolean::unchecked_from_js(JsValue::from(b))
}
}
impl From<Boolean> for bool {
#[inline]
fn from(b: Boolean) -> bool {
b.value_of()
}
}
impl PartialEq<bool> for Boolean {
#[inline]
fn eq(&self, other: &bool) -> bool {
self.value_of() == *other
}
}
impl fmt::Debug for Boolean {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.value_of().fmt(f)
}
}
// DataView
#[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
@ -719,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.
@ -758,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
@ -773,8 +801,8 @@ extern "C" {
// Function
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object)]
#[derive(Clone, Debug)]
#[wasm_bindgen(extends = Object, is_type_of = JsValue::is_function)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub type Function;
/// The `Function` constructor creates a new `Function` object. Calling the
@ -869,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(unsafe { mem::transmute(val) })
} else {
None
}
val.dyn_ref()
}
}
@ -881,7 +905,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.
@ -909,7 +933,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.
@ -1001,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
@ -1011,6 +1036,26 @@ extern "C" {
pub fn next(this: &Iterator) -> Result<IteratorNext, JsValue>;
}
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::<MaybeIterator>();
it.next().is_function()
}
}
/// An iterator over the JS `Symbol.iterator` iteration protocol.
///
/// Use the `IntoIterator for &js_sys::Iterator` implementation to create this.
@ -1099,34 +1144,20 @@ impl IterState {
/// Create an iterator over `val` using the JS iteration protocol and
/// `Symbol.iterator`.
pub fn try_iter(val: &JsValue) -> Result<Option<IntoIter>, 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 = iter_fn.unchecked_into();
let it = iter_fn.call0(val)?;
if !it.is_object() {
return Ok(None);
}
let iter_fn: Function = match iter_fn.dyn_into() {
Ok(iter_fn) => iter_fn,
Err(_) => return Ok(None),
};
let next = it.unchecked_ref::<MaybeIterator>().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
@ -1135,7 +1166,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
@ -1157,8 +1189,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
@ -1405,8 +1437,8 @@ extern "C" {
// Number.
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(extends = Object)]
#[derive(Clone, Debug)]
#[wasm_bindgen(extends = Object, is_type_of = |v| v.as_f64().is_some())]
#[derive(Clone)]
pub type Number;
/// The Number.isFinite() method determines whether the passed value is a finite number.
@ -1441,6 +1473,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,11 +1533,43 @@ 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<Number> 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" {
#[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
@ -2091,13 +2156,22 @@ 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
}
}
}
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" {
@ -2128,7 +2202,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
@ -2147,7 +2221,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
@ -2161,8 +2235,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
@ -2321,7 +2395,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
@ -2498,7 +2572,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
@ -2588,7 +2662,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
@ -2608,7 +2682,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
@ -2627,7 +2701,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
@ -2642,7 +2716,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
@ -2686,7 +2760,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.
@ -2773,7 +2847,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
@ -2795,7 +2869,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
@ -2826,7 +2900,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
@ -2847,7 +2921,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
@ -2868,7 +2942,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
@ -2910,7 +2984,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
@ -2956,7 +3030,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
@ -2997,8 +3071,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
@ -3056,8 +3130,8 @@ extern "C" {
// JsString
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_name = String, extends = Object)]
#[derive(Clone)]
#[wasm_bindgen(js_name = String, extends = Object, is_type_of = JsValue::is_string)]
#[derive(Clone, PartialEq, Eq)]
pub type JsString;
/// The length property of a String object indicates the length of a string,
@ -3516,11 +3590,38 @@ 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(unsafe { mem::transmute(val) })
} else {
None
}
val.dyn_ref()
}
/// 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<Item = u16> + DoubleEndedIterator<Item = u16> + 'a {
(0..self.length()).map(move |i| self.char_code_at(i) as u16)
}
}
@ -3550,9 +3651,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))
}
}
@ -3583,6 +3682,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;

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-macro-support"
version = "0.2.40"
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.40" }
wasm-bindgen-shared = { path = "../shared", version = "=0.2.40" }
wasm-bindgen-backend = { path = "../backend", version = "=0.2.42" }
wasm-bindgen-shared = { path = "../shared", version = "=0.2.42" }

View File

@ -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)),
@ -241,6 +242,11 @@ impl Parse for BindgenAttr {
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
});
(@parser $variant:ident(Span, syn::Expr)) => ({
input.parse::<Token![=]>()?;
return Ok(BindgenAttr::$variant(attr_span, input.parse()?));
});
(@parser $variant:ident(Span, String, Span)) => ({
input.parse::<Token![=]>()?;
let (val, span) = match input.parse::<syn::LitStr>() {
@ -523,6 +529,7 @@ impl ConvertToAst<BindgenAttrs> 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();
@ -545,6 +552,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
attrs: self.attrs,
doc_comment: None,
instanceof_shim: shim,
is_type_of,
rust_name: self.ident,
js_name,
extends,
@ -904,7 +912,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(),
},
);

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-macro"
version = "0.2.40"
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.40" }
wasm-bindgen-macro-support = { path = "../macro-support", version = "=0.2.42" }
quote = "0.6"

View File

@ -0,0 +1,10 @@
#![crate_type = "rlib"]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct A {
pub field: String,
}

View File

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

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-shared"
version = "0.2.40"
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"

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-test-macro"
version = "0.2.40"
version = "0.2.42"
authors = ["The wasm-bindgen Developers"]
description = "Internal testing macro for wasm-bindgen"
license = "MIT/Apache-2.0"

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-test"
version = "0.2.40"
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.17' }
js-sys = { path = '../js-sys', version = '0.3.19' }
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.42' }
wasm-bindgen-futures = { path = '../futures', version = '0.3.19' }
wasm-bindgen-test-macro = { path = '../test-macro', version = '=0.2.42' }
[lib]
test = false

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-threads-xform"
version = "0.2.40"
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"

View File

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

View File

@ -0,0 +1,3 @@
import * as wbg from '../../pkg/web/typescript_tests';
const init: Promise<any> = wbg.init('.');

View File

@ -9,6 +9,6 @@
"baseUrl": "."
},
"include": [
"src/*.ts"
"src/**/*.ts"
]
}

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-wasm-interpreter"
version = "0.2.40"
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"

View File

@ -1,6 +1,6 @@
[package]
name = "web-sys"
version = "0.3.17"
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.40" }
wasm-bindgen-webidl = { path = "../webidl", version = "=0.2.42" }
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.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.40' }
wasm-bindgen-futures = { path = '../futures', version = '0.3.17' }
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

View File

@ -1,6 +1,6 @@
[package]
name = "wasm-bindgen-webidl"
version = "0.2.40"
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.40", path = "../backend" }
wasm-bindgen-backend = { version = "=0.2.42", path = "../backend" }
weedle = "0.8"

View File

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

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

@ -8,8 +8,8 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
js-sys = "0.3.17"
wasm-bindgen = "0.2.40"
js-sys = "0.3.19"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

@ -8,8 +8,8 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
js-sys = "0.3.17"
wasm-bindgen = "0.2.42"
js-sys = "0.3.19"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -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.42"
web-sys = { version = "0.3.19", features = ['console'] }

View File

@ -8,7 +8,7 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

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

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

@ -8,7 +8,7 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,8 +8,8 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
js-sys = "0.3.17"
wasm-bindgen = "0.2.40"
js-sys = "0.3.19"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,7 +8,7 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"
humantime = "1"
[dependencies.web-sys]

View File

@ -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.19"
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.42", features = ['serde-serialize'] }
wasm-bindgen-futures = "0.3.19"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,7 +8,7 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -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.19"
wasm-bindgen = "0.2.42"
askama = "0.7.2"
console_error_panic_hook = "0.1.5"

View File

@ -8,5 +8,5 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
js-sys = "0.3.17"
wasm-bindgen = "0.2.42"
js-sys = "0.3.19"

View File

@ -8,4 +8,4 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"

View File

@ -8,7 +8,7 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,8 +8,8 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
js-sys = "0.3.17"
wasm-bindgen = "0.2.40"
js-sys = "0.3.19"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

@ -8,7 +8,7 @@ edition = "2018"
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2.40"
wasm-bindgen = "0.2.42"
[dependencies.web-sys]
version = "0.3.4"

View File

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

View File

@ -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 (<28>, 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<Item = u16>`. 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.

View File

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

View File

@ -16,28 +16,35 @@ pub trait JsCast
where
Self: AsRef<JsValue> + Into<JsValue>,
{
/// Test whether this JS value is an instance of the type `T`.
/// Test whether this JS value has a type `T`.
///
/// This method performs a dynamic check (at runtime) using the JS
/// `instanceof` operator. This method returns `self instanceof T`.
fn is_instance_of<T>(&self) -> bool
/// 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<T>(&self) -> bool
where
T: JsCast,
{
T::instanceof(self.as_ref())
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 `self.is_instance_of::<T>()`
/// This method will return `Err(self)` if `self.has_type::<T>()`
/// 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<T>(self) -> Result<T, Self>
where
T: JsCast,
{
if self.is_instance_of::<T>() {
if self.has_type::<T>() {
Ok(self.unchecked_into())
} else {
Err(self)
@ -47,14 +54,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::<T>()`
/// This method will return `None` if `self.has_type::<T>()`
/// 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<T>(&self) -> Option<&T>
where
T: JsCast,
{
if self.is_instance_of::<T>() {
if self.has_type::<T>() {
Some(self.unchecked_ref())
} else {
None
@ -93,13 +100,43 @@ 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<T>(&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
/// is a value of this type.
///
/// 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)
}
/// Performs a zero-cost unchecked conversion from a `JsValue` into an
/// instance of `Self`
///

View File

@ -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<A, R> WasmClosure for Fn(&A) -> R
where A: RefFromWasmAbi,
R: ReturnWasmAbi + 'static,
{
fn describe() {
#[allow(non_snake_case)]
unsafe extern "C" fn invoke<A: RefFromWasmAbi, R: ReturnWasmAbi>(
a: usize,
b: usize,
arg: <A as RefFromWasmAbi>::Abi,
) -> <R as ReturnWasmAbi>::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 = <A as RefFromWasmAbi>::ref_from_abi(arg, &mut _stack);
(*f)(&*arg)
};
ret.return_abi(&mut GlobalStack::new())
}
inform(invoke::<A, R> as u32);
unsafe extern fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(
a: usize,
b: usize,
) {
debug_assert!(a != 0, "should never destroy a Fn whose pointer is 0");
drop(Box::from_raw(FatPtr::<Fn(&A) -> R> {
fields: (a, b)
}.ptr));
}
inform(destroy::<A, R> as u32);
<&Self>::describe();
}
}
unsafe impl<A, R> WasmClosure for FnMut(&A) -> R
where A: RefFromWasmAbi,
R: ReturnWasmAbi + 'static,
{
fn describe() {
#[allow(non_snake_case)]
unsafe extern "C" fn invoke<A: RefFromWasmAbi, R: ReturnWasmAbi>(
a: usize,
b: usize,
arg: <A as RefFromWasmAbi>::Abi,
) -> <R as ReturnWasmAbi>::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 = <A as RefFromWasmAbi>::ref_from_abi(arg, &mut _stack);
(*f)(&*arg)
};
ret.return_abi(&mut GlobalStack::new())
}
inform(invoke::<A, R> as u32);
unsafe extern fn destroy<A: RefFromWasmAbi, R: ReturnWasmAbi>(
a: usize,
b: usize,
) {
debug_assert!(a != 0, "should never destroy a FnMut whose pointer is 0");
drop(Box::from_raw(FatPtr::<FnMut(&A) -> R> {
fields: (a, b)
}.ptr));
}
inform(destroy::<A, R> as u32);
<&mut Self>::describe();
}
}
#[allow(non_snake_case)]
impl<T, A, R> 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<Self::FnMut> {
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<FnMut(&A) -> 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
}
}

View File

@ -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: RefFromWasmAbi, R: ReturnWasmAbi>(
a: usize,
b: usize,
arg: <A as RefFromWasmAbi>::Abi,
) -> <R as ReturnWasmAbi>::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 = <A as RefFromWasmAbi>::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::<A, R> as u32);
inform(1);
<&A as WasmDescribe>::describe();
<R as WasmDescribe>::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: RefFromWasmAbi, R: ReturnWasmAbi>(
a: usize,
b: usize,
arg: <A as RefFromWasmAbi>::Abi,
) -> <R as ReturnWasmAbi>::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 = <A as RefFromWasmAbi>::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::<A, R> as u32);
inform(1);
<&A as WasmDescribe>::describe();
<R as WasmDescribe>::describe();
}
}

View File

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

View File

@ -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<String> {
unsafe {
@ -507,6 +517,7 @@ externs! {
fn __wbindgen_memory() -> u32;
fn __wbindgen_module() -> u32;
fn __wbindgen_function_table() -> u32;
}
}
@ -726,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};

View File

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

View File

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

View File

@ -461,3 +461,21 @@ pub fn option_class_assert_none(x: Option<OptionClass>) {
pub fn option_class_assert_some(x: Option<OptionClass>) {
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) {
}
}
}

View File

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

View File

@ -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<FnMut(&RefFirstArgument)>,
c: &Closure<FnMut(&RefFirstArgument)>,
);
#[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(&JsValue)>);
fn ref_first_arg4(a: &Closure<FnMut(&JsValue)>);
fn ref_first_custom1(a: &Fn(&RefFirstArgument));
fn ref_first_custom2(a: &mut FnMut(&RefFirstArgument));
fn ref_first_custom3(a: &Closure<Fn(&RefFirstArgument)>);
fn ref_first_custom4(a: &Closure<FnMut(&RefFirstArgument)>);
}
Closure::wrap(Box::new(|_: &JsValue| ()) as Box<Fn(&JsValue)>);
Closure::wrap(Box::new(|_: &JsValue| ()) as Box<FnMut(&JsValue)>);
Closure::once(|_: &JsValue| ());
Closure::once_into_js(|_: &JsValue| ());
Closure::wrap(Box::new(|_: &RefFirstArgument| ()) as Box<Fn(&RefFirstArgument)>);
Closure::wrap(Box::new(|_: &RefFirstArgument| ()) as Box<FnMut(&RefFirstArgument)>);
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);
}

View File

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

View File

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