Merge remote-tracking branch 'upstream/master'

# Conflicts:
#	crates/webidl/src/first_pass.rs
#	crates/webidl/src/lib.rs
#	crates/webidl/src/util.rs
This commit is contained in:
Anton Danilkin 2018-08-06 22:07:36 +03:00
commit ef3f086102
73 changed files with 2203 additions and 2619 deletions

View File

@ -52,6 +52,9 @@ matrix:
script:
- cargo test --release
- cargo test --target wasm32-unknown-unknown
- WASM_BINDGEN_NO_DEBUG=1 cargo test --target wasm32-unknown-unknown
- cargo test --target wasm32-unknown-unknown --features serde-serialize
- cargo test --target wasm32-unknown-unknown -p no-std
# Check JS output from all tests against eslint
- npm run run-lint-generated-tests
# Check Examples against eslint

View File

@ -33,6 +33,9 @@ serde_json = { version = "1.0", optional = true }
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { path = 'crates/test', version = '=0.2.15' }
serde_derive = "1.0"
wasm-bindgen-test-crate-a = { path = 'tests/crates/a' }
wasm-bindgen-test-crate-b = { path = 'tests/crates/b' }
[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
wasm-bindgen-test-project-builder = { path = "crates/test-project-builder", version = '=0.2.15' }
@ -63,6 +66,7 @@ members = [
"examples/performance",
"examples/smorgasboard",
"examples/wasm-in-wasm",
"tests/no-std",
]
[patch.crates-io]

View File

@ -56,7 +56,6 @@ pub enum MethodSelf {
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
pub struct Import {
pub module: Option<String>,
pub version: Option<String>,
pub js_namespace: Option<Ident>,
pub kind: ImportKind,
}
@ -119,7 +118,7 @@ pub struct ImportStatic {
pub ty: syn::Type,
pub shim: Ident,
pub rust_name: Ident,
pub js_name: Ident,
pub js_name: String,
}
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
@ -146,7 +145,7 @@ pub struct ImportEnum {
#[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))]
pub struct Function {
pub name: Ident,
pub name: String,
pub arguments: Vec<syn::ArgCaptured>,
pub ret: Option<syn::Type>,
pub rust_attrs: Vec<syn::Attribute>,
@ -304,33 +303,8 @@ impl Variant {
impl Import {
fn shared(&self) -> Result<shared::Import, Diagnostic> {
match (&self.module, &self.version) {
(&Some(ref m), None) if m.starts_with("./") => {}
(&Some(ref m), &Some(_)) if m.starts_with("./") => {
panic!(
"when a module path starts with `./` that indicates \
that a local file is being imported so the `version` \
key cannot also be specified"
);
}
(&Some(_), &Some(_)) => {}
(&Some(_), &None) => panic!(
"when the `module` directive doesn't start with `./` \
then it's interpreted as an NPM package which requires \
a `version` to be specified as well, try using \
#[wasm_bindgen(module = \"...\", version = \"...\")]"
),
(&None, &Some(_)) => {
panic!(
"the #[wasm_bindgen(version = \"...\")] attribute can only \
be used when `module = \"...\"` is also specified"
);
}
(&None, &None) => {}
}
Ok(shared::Import {
module: self.module.clone(),
version: self.version.clone(),
js_namespace: self.js_namespace.as_ref().map(|s| s.to_string()),
kind: self.kind.shared(),
})

View File

@ -94,7 +94,6 @@ pub fn ident_ty(ident: Ident) -> syn::Type {
pub fn wrap_import_function(function: ast::ImportFunction) -> ast::Import {
ast::Import {
module: None,
version: None,
js_namespace: None,
kind: ast::ImportKind::Function(function),
}

View File

@ -15,7 +15,6 @@ base64 = "0.9"
failure = "0.1.2"
parity-wasm = "0.31"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
tempfile = "3.0"
wasm-bindgen-shared = { path = "../shared", version = '=0.2.15' }

View File

@ -5,7 +5,6 @@ use std::mem;
use failure::{Error, ResultExt};
use parity_wasm;
use parity_wasm::elements::*;
use serde_json;
use shared;
use wasm_gc;
@ -43,7 +42,6 @@ pub struct Context<'a> {
pub exported_classes: HashMap<String, ExportedClass>,
pub function_table_needed: bool,
pub run_descriptor: &'a Fn(&str) -> Option<Vec<u32>>,
pub module_versions: Vec<(String, String)>,
}
#[derive(Default)]
@ -458,7 +456,6 @@ impl<'a> Context<'a> {
self.export_table();
self.gc()?;
self.add_wasm_pack_section();
while js.contains("\n\n\n") {
js = js.replace("\n\n\n", "\n\n");
@ -1629,28 +1626,6 @@ impl<'a> Context<'a> {
self.globals.push_str("\n");
}
fn add_wasm_pack_section(&mut self) {
if self.module_versions.len() == 0 {
return;
}
#[derive(Serialize)]
struct WasmPackSchema<'a> {
version: &'a str,
modules: &'a [(String, String)],
}
let contents = serde_json::to_string(&WasmPackSchema {
version: "0.0.1",
modules: &self.module_versions,
}).unwrap();
let mut section = CustomSection::default();
*section.name_mut() = "__wasm_pack_unstable".to_string();
*section.payload_mut() = contents.into_bytes();
self.module.sections_mut().push(Section::Custom(section));
}
fn use_node_require(&self) -> bool {
self.config.nodejs && !self.config.nodejs_experimental_modules
}
@ -1766,7 +1741,6 @@ impl<'a, 'b> SubContext<'a, 'b> {
}
fn generate_import(&mut self, import: &shared::Import) -> Result<(), Error> {
self.validate_import_module(import)?;
match import.kind {
shared::ImportKind::Function(ref f) => {
self.generate_import_function(import, f).with_context(|_| {
@ -1787,41 +1761,6 @@ impl<'a, 'b> SubContext<'a, 'b> {
Ok(())
}
fn validate_import_module(&mut self, import: &shared::Import) -> Result<(), Error> {
let version = match import.version {
Some(ref s) => s,
None => return Ok(()),
};
let module = match import.module {
Some(ref s) => s,
None => return Ok(()),
};
if module.starts_with("./") {
return Ok(());
}
let pkg = if module.starts_with("@") {
// Translate `@foo/bar/baz` to `@foo/bar` and `@foo/bar` to itself
let first_slash = match module.find('/') {
Some(i) => i,
None => bail!(
"packages starting with `@` must be of the form \
`@foo/bar`, but found: `{}`",
module
),
};
match module[first_slash + 1..].find('/') {
Some(i) => &module[..i],
None => module,
}
} else {
module.split('/').next().unwrap()
};
self.cx
.module_versions
.push((pkg.to_string(), version.clone()));
Ok(())
}
fn generate_import_static(
&mut self,
info: &shared::Import,

View File

@ -2,8 +2,6 @@
extern crate parity_wasm;
extern crate wasm_bindgen_shared as shared;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate wasm_gc;
extern crate wasmi;
@ -203,7 +201,6 @@ impl Bindgen {
config: &self,
module: &mut module,
function_table_needed: false,
module_versions: Default::default(),
run_descriptor: &|name| {
let mut v = MyExternals(Vec::new());
match instance.invoke_export(name, &[], &mut v) {

View File

@ -123,11 +123,12 @@ fn rmain() -> Result<(), Error> {
node = !custom.payload().contains(&0x01);
}
let headless = env::var("NO_HEADLESS").is_err();
let debug = env::var("WASM_BINDGEN_NO_DEBUG").is_err();
// Make the generated bindings available for the tests to execute against.
shell.status("Executing bindgen...");
let mut b = Bindgen::new();
b.debug(true)
b.debug(debug)
.nodejs(node)
.input_module(module, wasm, |w| parity_wasm::serialize(w).unwrap())
.keep_debug(false)

View File

@ -361,6 +361,16 @@ extern "C" {
#[wasm_bindgen(constructor)]
pub fn new(length: u32) -> ArrayBuffer;
/// The byteLength property of an object which is an instance of type ArrayBuffer
/// it's an accessor property whose set accessor function is undefined,
/// meaning that you can only read this property.
/// The value is established when the array is constructed and cannot be changed.
/// This property returns 0 if this ArrayBuffer has been detached.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/byteLength
#[wasm_bindgen(method, getter, js_name = byteLength)]
pub fn byte_length(this: &ArrayBuffer) -> u32;
/// The `isView()` method returns true if arg is one of the `ArrayBuffer`
/// views, such as typed array objects or a DataView; false otherwise.
///
@ -2168,6 +2178,30 @@ extern {
#[wasm_bindgen(method, getter)]
pub fn multiline(this: &RegExp) -> bool;
/// The non-standard $1, $2, $3, $4, $5, $6, $7, $8, $9 properties
/// are static and read-only properties of regular expressions
/// that contain parenthesized substring matches.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/n
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$1")]
pub fn n1() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$2")]
pub fn n2() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$3")]
pub fn n3() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$4")]
pub fn n4() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$5")]
pub fn n5() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$6")]
pub fn n6() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$7")]
pub fn n7() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$8")]
pub fn n8() -> JsString;
#[wasm_bindgen(static_method_of = RegExp, getter, js_name = "$9")]
pub fn n9() -> JsString;
/// The RegExp constructor creates a regular expression object for matching text with a pattern.
///
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp

View File

@ -9,6 +9,12 @@ fn new() {
assert!(y.is_object());
}
#[wasm_bindgen_test]
fn byte_length() {
let buf = ArrayBuffer::new(42);
assert_eq!(buf.byte_length(), 42);
}
#[wasm_bindgen_test]
fn is_view() {
let x = Uint8Array::new(&JsValue::from(42));

View File

@ -29,7 +29,7 @@ fn apply() {
assert_eq!(Array::from(&arr).length(), 1);
}
#[wasm_bindgen(module = "tests/wasm/Function.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/Function.js")]
extern {
fn get_function_to_bind() -> Function;
fn get_value_to_bind_to() -> JsValue;

View File

@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use js_sys::*;
#[wasm_bindgen(module = "tests/wasm/Generator.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/Generator.js")]
extern {
fn one_two_generator() -> Generator;
fn dummy_generator() -> Generator;

View File

@ -10,7 +10,7 @@ extern {
fn set_foo(this: &Foo42, val: JsValue);
}
#[wasm_bindgen(module = "tests/wasm/Object.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/Object.js")]
extern {
fn map_with_symbol_key() -> Object;
fn symbol_key() -> JsValue;

View File

@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use js_sys::*;
#[wasm_bindgen(module = "tests/wasm/Proxy.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/Proxy.js")]
extern {
fn proxy_target() -> JsValue;
fn proxy_handler() -> Object;

View File

@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use js_sys::*;
#[wasm_bindgen(module = "tests/wasm/Reflect.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/Reflect.js")]
extern {
fn get_char_at() -> Function;

View File

@ -3,7 +3,6 @@ use js_sys::*;
#[wasm_bindgen_test]
fn exec() {
let re = RegExp::new("quick\\s(brown).+?(jumps)", "ig");
let result = re.exec("The Quick Brown Fox Jumps Over The Lazy Dog");
@ -76,6 +75,21 @@ fn multiline() {
assert!(re.multiline());
}
#[wasm_bindgen_test]
fn n1_to_n9() {
let re = RegExp::new(r"(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)\s(\w+)", "");
re.test("The Quick Brown Fox Jumps Over The Lazy Dog");
assert_eq!(RegExp::n1(), "The");
assert_eq!(RegExp::n2(), "Quick");
assert_eq!(RegExp::n3(), "Brown");
assert_eq!(RegExp::n4(), "Fox");
assert_eq!(RegExp::n5(), "Jumps");
assert_eq!(RegExp::n6(), "Over");
assert_eq!(RegExp::n7(), "The");
assert_eq!(RegExp::n8(), "Lazy");
assert_eq!(RegExp::n9(), "Dog");
}
#[wasm_bindgen_test]
fn new() {
let re = RegExp::new("foo", "");

View File

@ -2,7 +2,7 @@ use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use js_sys::*;
#[wasm_bindgen(module = "tests/wasm/Symbol.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/Symbol.js")]
extern {
fn test_has_instance(sym: &Symbol);
fn test_is_concat_spreadable(sym: &Symbol);

View File

@ -53,17 +53,6 @@ impl BindgenAttrs {
.next()
}
/// Get the first version attribute
fn version(&self) -> Option<&str> {
self.attrs
.iter()
.filter_map(|a| match a {
BindgenAttr::Version(s) => Some(&s[..]),
_ => None,
})
.next()
}
/// Whether the catch attribute is present
fn catch(&self) -> bool {
self.attrs.iter().any(|a| match a {
@ -173,11 +162,11 @@ impl BindgenAttrs {
}
/// Get the first js_name attribute
fn js_name(&self) -> Option<&Ident> {
fn js_name(&self) -> Option<&str> {
self.attrs
.iter()
.filter_map(|a| match a {
BindgenAttr::JsName(s) => Some(s),
BindgenAttr::JsName(s) => Some(&s[..]),
_ => None,
})
.next()
@ -219,7 +208,6 @@ pub enum BindgenAttr {
StaticMethodOf(Ident),
JsNamespace(Ident),
Module(String),
Version(String),
Getter(Option<Ident>),
Setter(Option<Ident>),
SpecialGetter,
@ -227,7 +215,7 @@ pub enum BindgenAttr {
SpecialDeleter,
Structural,
Readonly,
JsName(Ident),
JsName(String),
JsClass(String),
}
@ -290,18 +278,15 @@ impl syn::synom::Synom for BindgenAttr {
(s.value())
)=> { BindgenAttr::Module }
|
do_parse!(
call!(term, "version") >>
punct!(=) >>
s: syn!(syn::LitStr) >>
(s.value())
)=> { BindgenAttr::Version }
|
do_parse!(
call!(term, "js_name") >>
punct!(=) >>
ns: call!(term2ident) >>
(ns)
name: alt!(
syn!(syn::LitStr) => { |s| s.value() }
|
call!(term2ident) => { |s| s.to_string() }
) >>
(name)
)=> { BindgenAttr::JsName }
|
do_parse!(
@ -398,9 +383,10 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
fn convert(self, (opts, module): (BindgenAttrs, &'a Option<String>))
-> Result<Self::Target, Diagnostic>
{
let js_name = opts.js_name().unwrap_or(&self.ident).clone();
let default_name = self.ident.to_string();
let js_name = opts.js_name().unwrap_or(&default_name);
let wasm = function_from_decl(
&js_name,
js_name,
self.decl.clone(),
self.attrs.clone(),
self.vis.clone(),
@ -517,7 +503,9 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
ast::ImportFunctionKind::Method { ref class, .. } => (1, &class[..]),
};
let data = (ns, &self.ident, module);
format!("__wbg_{}_{}", js_name, ShortHash(data))
format!("__wbg_{}_{}",
js_name.chars().filter(|c| c.is_ascii_alphanumeric()).collect::<String>(),
ShortHash(data))
};
Ok(ast::ImportKind::Function(ast::ImportFunction {
function: wasm,
@ -552,13 +540,16 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemStatic {
if self.mutability.is_some() {
bail_span!(self.mutability, "cannot import mutable globals yet")
}
let js_name = opts.js_name().unwrap_or(&self.ident);
let shim = format!("__wbg_static_accessor_{}_{}", js_name, self.ident);
let default_name = self.ident.to_string();
let js_name = opts.js_name().unwrap_or(&default_name);
let shim = format!("__wbg_static_accessor_{}_{}",
js_name.chars().filter(|c| c.is_ascii_alphanumeric()).collect::<String>(),
self.ident);
Ok(ast::ImportKind::Static(ast::ImportStatic {
ty: *self.ty,
vis: self.vis,
rust_name: self.ident.clone(),
js_name: js_name.clone(),
js_name: js_name.to_string(),
shim: Ident::new(&shim, Span::call_site()),
}))
}
@ -579,14 +570,15 @@ impl ConvertToAst<BindgenAttrs> for syn::ItemFn {
bail_span!(self.unsafety, "can only #[wasm_bindgen] safe functions");
}
let name = attrs.js_name().unwrap_or(&self.ident);
let default_name = self.ident.to_string();
let name = attrs.js_name().unwrap_or(&default_name);
Ok(function_from_decl(name, self.decl, self.attrs, self.vis, false, None)?.0)
}
}
/// Construct a function (and gets the self type if appropriate) for our AST from a syn function.
fn function_from_decl(
name: &Ident,
name: &str,
decl: Box<syn::FnDecl>,
attrs: Vec<syn::Attribute>,
vis: syn::Visibility,
@ -661,7 +653,7 @@ fn function_from_decl(
Ok((
ast::Function {
name: name.clone(),
name: name.to_string(),
arguments,
ret,
rust_vis: vis,
@ -824,7 +816,7 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) {
};
let (function, method_self) = function_from_decl(
opts.js_name().unwrap_or(&method.sig.ident),
opts.js_name().unwrap_or(&method.sig.ident.to_string()),
Box::new(method.sig.decl.clone()),
method.attrs.clone(),
method.vis.clone(),
@ -940,10 +932,6 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
BindgenAttrs::find(attrs)?
};
let module = item_opts.module().or(opts.module()).map(|s| s.to_string());
let version = item_opts
.version()
.or(opts.version())
.map(|s| s.to_string());
let js_namespace = item_opts.js_namespace().or(opts.js_namespace()).cloned();
let kind = match self {
syn::ForeignItem::Fn(f) => f.convert((item_opts, &module))?,
@ -954,7 +942,6 @@ impl<'a> MacroParse<&'a BindgenAttrs> for syn::ForeignItem {
program.imports.push(ast::Import {
module,
version,
js_namespace,
kind,
});

View File

@ -24,7 +24,6 @@ pub struct Program {
#[derive(Deserialize, Serialize)]
pub struct Import {
pub module: Option<String>,
pub version: Option<String>,
pub js_namespace: Option<String>,
pub kind: ImportKind,
}

View File

@ -32,9 +32,16 @@ pub fn wasm_bindgen_test(
let mut body = TokenStream::from(body).into_iter();
// Assume the input item is of the form `fn #ident ...`, and extract
// `#ident`
let fn_tok = body.next();
// Skip over other attributes to `fn #ident ...`, and extract `#ident`
let mut leading_tokens = Vec::new();
while let Some(token) = body.next() {
leading_tokens.push(token.clone());
if let TokenTree::Ident(token) = token {
if token == "fn" {
break
}
}
}
let ident = match body.next() {
Some(TokenTree::Ident(token)) => token,
_ => panic!("expected a function name"),
@ -64,7 +71,7 @@ pub fn wasm_bindgen_test(
}
}).into_iter());
tokens.extend(fn_tok);
tokens.extend(leading_tokens);
tokens.push(ident.into());
tokens.extend(body);

View File

@ -1,4 +1,5 @@
extern crate env_logger;
#[macro_use]
extern crate failure;
extern crate wasm_bindgen_webidl;
extern crate sourcefile;
@ -8,9 +9,8 @@ use sourcefile::SourceFile;
use std::env;
use std::ffi::OsStr;
use std::fs;
use std::io::Write;
use std::path;
use std::process;
use std::process::{self, Command};
fn main() {
if let Err(e) = try_main() {
@ -32,12 +32,14 @@ fn try_main() -> Result<(), failure::Error> {
let mut source = SourceFile::default();
for entry in entries {
let entry = entry.context("getting webidls/enabled/*.webidl entry")?;
if entry.path().extension() == Some(OsStr::new("webidl")) {
println!("cargo:rerun-if-changed={}", entry.path().display());
source = source.add_file(entry.path())
.with_context(|_| format!("reading contents of file \"{}\"",
entry.path().display()))?;
let path = entry.path();
if path.extension() != Some(OsStr::new("webidl")) {
continue
}
println!("cargo:rerun-if-changed={}", path.display());
source = source.add_file(&path)
.with_context(|_| format!("reading contents of file \"{}\"",
path.display()))?;
}
let bindings = match wasm_bindgen_webidl::compile(&source.contents) {
@ -60,17 +62,19 @@ fn try_main() -> Result<(), failure::Error> {
let out_dir = env::var("OUT_DIR").context("reading OUT_DIR environment variable")?;
let out_file_path = path::Path::new(&out_dir).join("bindings.rs");
let mut out_file = fs::File::create(&out_file_path)
.context("creating output bindings file")?;
out_file
.write_all(bindings.as_bytes())
fs::write(&out_file_path, bindings)
.context("writing bindings to output file")?;
// run rustfmt on the generated file - really handy for debugging
//if ! process::Command::new("rustfmt").arg(&out_file_path).status()
// .context("running rustfmt")?.success() {
// return Err(format_err!("rustfmt failed to format {}", out_file_path.display()));
//}
if env::var("WEBIDL_RUSTFMT_BINDINGS").is_ok() {
let status = Command::new("rustfmt")
.arg(&out_file_path)
.status()
.context("running rustfmt")?;
if !status.success() {
bail!("rustfmt failed: {}", status)
}
}
Ok(())
}

View File

@ -28,7 +28,7 @@ fn main() {
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
#[wasm_bindgen(module = "{}", version = "*")]
#[wasm_bindgen(module = "{}")]
extern {{
fn not_actually_a_function{1}();
}}

View File

@ -20,4 +20,4 @@ proc-macro2 = "0.4.8"
quote = '0.6'
syn = { version = '0.14', features = ['full'] }
wasm-bindgen-backend = { version = "=0.2.15", path = "../backend" }
webidl = "0.7.0"
weedle = "0.6"

View File

@ -7,69 +7,61 @@
//! Only `interface`s, `dictionary`s, `enum`s and `mixin`s can
//! be partial.
use std::{
collections::{BTreeMap, BTreeSet}, mem,
};
use std::collections::{BTreeMap, BTreeSet};
use webidl;
use weedle::argument::Argument;
use weedle::attribute::ExtendedAttribute;
use weedle::interface::StringifierOrStatic;
use weedle::mixin::MixinMembers;
use weedle;
use super::Result;
use util;
/// Collection of constructs that may use partial.
#[derive(Default)]
pub(crate) struct FirstPassRecord<'a> {
pub(crate) interfaces: BTreeMap<String, InterfaceData>,
pub(crate) dictionaries: BTreeSet<String>,
pub(crate) enums: BTreeSet<String>,
pub(crate) struct FirstPassRecord<'src> {
pub(crate) interfaces: BTreeMap<&'src str, InterfaceData<'src>>,
pub(crate) dictionaries: BTreeSet<&'src str>,
pub(crate) enums: BTreeSet<&'src str>,
/// The mixins, mapping their name to the webidl ast node for the mixin.
pub(crate) mixins: BTreeMap<String, MixinData<'a>>,
pub(crate) typedefs: BTreeMap<String, webidl::ast::Type>,
pub(crate) mixins: BTreeMap<&'src str, Vec<&'src MixinMembers<'src>>>,
pub(crate) typedefs: BTreeMap<&'src str, &'src weedle::types::Type<'src>>,
}
/// We need to collect interface data during the first pass, to be used later.
#[derive(Default)]
pub(crate) struct InterfaceData {
pub(crate) struct InterfaceData<'src> {
/// Whether only partial interfaces were encountered
pub(crate) partial: bool,
pub(crate) operations: BTreeMap<OperationId, OperationData>,
pub(crate) global: bool,
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
}
#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum OperationId {
pub(crate) enum OperationId<'src> {
Constructor,
Operation(Option<String>),
Operation(Option<&'src str>),
SpecialGetter,
SpecialSetter,
SpecialDeleter,
}
#[derive(Default)]
pub(crate) struct OperationData {
pub(crate) struct OperationData<'src> {
pub(crate) overloaded: bool,
/// Map from argument names to whether they are the same for multiple overloads
pub(crate) argument_names_same: BTreeMap<Vec<String>, bool>,
}
/// We need to collect mixin data during the first pass, to be used later.
#[derive(Default)]
pub(crate) struct MixinData<'a> {
/// The non partial mixin, if present. If there is more than one, we are
/// parsing is a malformed WebIDL file, but the parser will recover by
/// using the last parsed mixin.
pub(crate) non_partial: Option<&'a webidl::ast::NonPartialMixin>,
/// 0 or more partial mixins.
pub(crate) partials: Vec<&'a webidl::ast::PartialMixin>,
pub(crate) argument_names_same: BTreeMap<Vec<&'src str>, bool>,
}
/// Implemented on an AST node to populate the `FirstPassRecord` struct.
pub(crate) trait FirstPass<Ctx> {
pub(crate) trait FirstPass<'src, Ctx> {
/// Populate `record` with any constructs in `self`.
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, ctx: Ctx) -> Result<()>;
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, ctx: Ctx) -> Result<()>;
}
impl FirstPass<()> for [webidl::ast::Definition] {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
impl<'src> FirstPass<'src, ()> for [weedle::Definition<'src>] {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
for def in self {
def.first_pass(record, ())?;
}
@ -78,15 +70,17 @@ impl FirstPass<()> for [webidl::ast::Definition] {
}
}
impl FirstPass<()> for webidl::ast::Definition {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
use webidl::ast::Definition::*;
impl<'src> FirstPass<'src, ()> for weedle::Definition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
use weedle::Definition::*;
match self {
Dictionary(dictionary) => dictionary.first_pass(record, ()),
Enum(enum_) => enum_.first_pass(record, ()),
Interface(interface) => interface.first_pass(record, ()),
Mixin(mixin) => mixin.first_pass(record, ()),
PartialInterface(interface) => interface.first_pass(record, ()),
InterfaceMixin(mixin) => mixin.first_pass(record, ()),
PartialInterfaceMixin(mixin) => mixin.first_pass(record, ()),
Typedef(typedef) => typedef.first_pass(record, ()),
_ => {
// Other definitions aren't currently used in the first pass
@ -96,46 +90,38 @@ impl FirstPass<()> for webidl::ast::Definition {
}
}
impl FirstPass<()> for webidl::ast::Dictionary {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
use webidl::ast::Dictionary::*;
match self {
NonPartial(dictionary) => dictionary.first_pass(record, ()),
_ => {
// Other dictionaries aren't currently used in the first pass
Ok(())
}
impl<'src> FirstPass<'src, ()> for weedle::DictionaryDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
if !record.dictionaries.insert(self.identifier.0) {
warn!("encountered multiple dictionary declarations of {}", self.identifier.0);
}
Ok(())
}
}
impl FirstPass<()> for webidl::ast::NonPartialDictionary {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
if record.dictionaries.insert(self.name.clone()) {
warn!("Encountered multiple declarations of {}", self.name);
impl<'src> FirstPass<'src, ()> for weedle::EnumDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
if !record.enums.insert(self.identifier.0) {
warn!("Encountered multiple enum declarations of {}", self.identifier.0);
}
Ok(())
}
}
impl FirstPass<()> for webidl::ast::Enum {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
if record.enums.insert(self.name.clone()) {
warn!("Encountered multiple declarations of {}", self.name);
}
Ok(())
}
}
fn first_pass_operation<'a>(
record: &mut FirstPassRecord<'a>,
self_name: &str,
id: OperationId,
arguments: &[webidl::ast::Argument],
fn first_pass_operation<'src>(
record: &mut FirstPassRecord<'src>,
self_name: &'src str,
id: OperationId<'src>,
arguments: &[Argument<'src>],
) -> Result<()> {
let mut names = Vec::with_capacity(arguments.len());
for argument in arguments {
match argument {
Argument::Single(arg) => names.push(arg.identifier.0),
Argument::Variadic(_) => return Ok(()),
}
}
record
.interfaces
.get_mut(self_name)
@ -143,77 +129,48 @@ fn first_pass_operation<'a>(
.operations
.entry(id)
.and_modify(|operation_data| operation_data.overloaded = true)
.or_insert_with(||
OperationData {
overloaded: false,
argument_names_same: Default::default(),
}
)
.or_insert_with(Default::default)
.argument_names_same
.entry(arguments.iter().map(|argument| argument.name.clone()).collect())
.entry(names)
.and_modify(|same_argument_names| *same_argument_names = true)
.or_insert(false);
Ok(())
}
impl FirstPass<()> for webidl::ast::Interface {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
use webidl::ast::Interface::*;
match self {
Partial(interface) => interface.first_pass(record, ()),
NonPartial(interface) => interface.first_pass(record, ()),
// TODO
Callback(..) => {
warn!("Unsupported WebIDL interface: {:?}", self);
Ok(())
}
impl<'src> FirstPass<'src, ()> for weedle::InterfaceDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
{
let interface = record
.interfaces
.entry(self.identifier.0)
.or_insert_with(Default::default);
interface.partial = false;
}
}
}
impl FirstPass<()> for webidl::ast::NonPartialInterface {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
record
.interfaces
.entry(self.name.clone())
.and_modify(|interface_data| {
if interface_data.partial {
interface_data.partial = false;
} else {
warn!("Encountered multiple declarations of {}", self.name);
}
})
.or_insert_with(||
InterfaceData {
partial: false,
operations: Default::default(),
global: false,
},
);
if ::util::is_chrome_only(&self.extended_attributes) {
if util::is_chrome_only(&self.attributes) {
return Ok(())
}
for extended_attribute in &self.extended_attributes {
extended_attribute.first_pass(record, &self.name)?;
if let Some(attrs) = &self.attributes {
for attr in &attrs.body.list {
attr.first_pass(record, self.identifier.0)?;
}
}
for member in &self.members {
member.first_pass(record, &self.name)?;
for member in &self.members.body {
member.first_pass(record, self.identifier.0)?;
}
Ok(())
}
}
impl FirstPass<()> for webidl::ast::PartialInterface {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
record
.interfaces
.entry(self.name.clone())
.entry(self.identifier.0)
.or_insert_with(||
InterfaceData {
partial: true,
@ -222,191 +179,129 @@ impl FirstPass<()> for webidl::ast::PartialInterface {
},
);
if ::util::is_chrome_only(&self.extended_attributes) {
if util::is_chrome_only(&self.attributes) {
return Ok(())
}
for member in &self.members {
member.first_pass(record, &self.name)?;
for member in &self.members.body {
member.first_pass(record, self.identifier.0)?;
}
Ok(())
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::ExtendedAttribute {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
impl<'src> FirstPass<'src, &'src str> for ExtendedAttribute<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
match self {
webidl::ast::ExtendedAttribute::ArgumentList(
webidl::ast::ArgumentListExtendedAttribute { arguments, name },
)
if name == "Constructor" =>
{
first_pass_operation(
record,
self_name,
OperationId::Constructor,
&arguments,
)
}
webidl::ast::ExtendedAttribute::NoArguments(webidl::ast::Other::Identifier(name))
if name == "Constructor" =>
{
first_pass_operation(
record,
self_name,
OperationId::Constructor,
&[],
)
}
webidl::ast::ExtendedAttribute::NamedArgumentList(
webidl::ast::NamedArgumentListExtendedAttribute {
lhs_name,
rhs_arguments,
..
},
)
if lhs_name == "NamedConstructor" =>
{
first_pass_operation(
record,
self_name,
OperationId::Constructor,
&rhs_arguments,
)
},
webidl::ast::ExtendedAttribute::Identifier(
webidl::ast::IdentifierExtendedAttribute { lhs, .. }
)
| webidl::ast::ExtendedAttribute::IdentifierList(
webidl::ast::IdentifierListExtendedAttribute { lhs, .. }
)
if lhs == "Global" =>
{
record.interfaces.get_mut(self_name).unwrap().global = true;
Ok(())
}
ExtendedAttribute::ArgList(list) if list.identifier.0 == "Constructor" => {
first_pass_operation(
record,
self_name,
OperationId::Constructor,
&list.args.body.list,
)
}
ExtendedAttribute::NoArgs(name) if (name.0).0 == "Constructor" => {
first_pass_operation(
record,
self_name,
OperationId::Constructor,
&[],
)
}
ExtendedAttribute::NamedArgList(list)
if list.lhs_identifier.0 == "NamedConstructor" =>
{
first_pass_operation(
record,
self_name,
OperationId::Constructor,
&list.args.body.list,
)
}
ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Global" => {
record.interfaces.get_mut(self_name).unwrap().global = true;
Ok(())
}
ExtendedAttribute::IdentList(id) if id.identifier.0 == "Global" => {
record.interfaces.get_mut(self_name).unwrap().global = true;
Ok(())
}
_ => Ok(())
}
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::InterfaceMember {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
impl<'src> FirstPass<'src, &'src str> for weedle::interface::InterfaceMember<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
match self {
webidl::ast::InterfaceMember::Operation(op) => op.first_pass(record, self_name),
weedle::interface::InterfaceMember::Operation(op) => {
op.first_pass(record, self_name)
}
_ => Ok(()),
}
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::Operation {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
match self {
webidl::ast::Operation::Regular(op) => op.first_pass(record, self_name),
webidl::ast::Operation::Static(op) => op.first_pass(record, self_name),
webidl::ast::Operation::Special(op) => op.first_pass(record, self_name),
// TODO
webidl::ast::Operation::Stringifier(_) => {
warn!("Unsupported WebIDL operation: {:?}", self);
Ok(())
}
impl<'src> FirstPass<'src, &'src str> for weedle::interface::OperationInterfaceMember<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, self_name: &'src str) -> Result<()> {
if !self.specials.is_empty() && self.specials.len() != 1 {
warn!("Unsupported webidl operation {:?}", self);
return Ok(())
}
if let Some(StringifierOrStatic::Stringifier(_)) = self.modifier {
warn!("Unsupported webidl operation {:?}", self);
return Ok(())
}
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::RegularOperation {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
first_pass_operation(
record,
self_name,
OperationId::Operation(self.name.clone()),
&self.arguments,
)
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::StaticOperation {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
first_pass_operation(
record,
self_name,
OperationId::Operation(self.name.clone()),
&self.arguments,
)
}
}
impl<'b> FirstPass<&'b str> for webidl::ast::SpecialOperation {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, self_name: &'b str) -> Result<()> {
first_pass_operation(
record,
self_name,
match self.name {
None => match self.special_keywords.iter().next() {
Some(webidl::ast::Special::Getter) => OperationId::SpecialGetter,
Some(webidl::ast::Special::Setter) => OperationId::SpecialSetter,
Some(webidl::ast::Special::Deleter) => OperationId::SpecialDeleter,
Some(webidl::ast::Special::LegacyCaller) => return Ok(()),
None => {
panic!("unsupported special operation: {:?} of {}", self, self_name);
}
match self.identifier.map(|s| s.0) {
None => match self.specials.get(0) {
None => OperationId::Operation(None),
Some(weedle::interface::Special::Getter(weedle::term::Getter)) => OperationId::SpecialGetter,
Some(weedle::interface::Special::Setter(weedle::term::Setter)) => OperationId::SpecialSetter,
Some(weedle::interface::Special::Deleter(weedle::term::Deleter)) => OperationId::SpecialDeleter,
Some(weedle::interface::Special::LegacyCaller(weedle::term::LegacyCaller)) => return Ok(()),
},
Some(ref name) => OperationId::Operation(Some(name.clone())),
},
&self.arguments,
&self.args.body.list,
)
}
}
impl FirstPass<()> for webidl::ast::Mixin {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
use webidl::ast::Mixin::*;
match self {
NonPartial(mixin) => mixin.first_pass(record, ()),
Partial(mixin) => mixin.first_pass(record, ()),
}
}
}
impl FirstPass<()> for webidl::ast::NonPartialMixin {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
let entry = record
impl<'src> FirstPass<'src, ()> for weedle::InterfaceMixinDefinition<'src>{
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
record
.mixins
.entry(self.name.clone())
.or_insert_with(Default::default);
if mem::replace(&mut entry.non_partial, Some(self)).is_some() {
warn!(
"Encounterd multiple declarations of {}, using last encountered",
self.name
);
}
.entry(self.identifier.0)
.or_insert_with(Default::default)
.push(&self.members.body);
Ok(())
}
}
impl FirstPass<()> for webidl::ast::PartialMixin {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
let entry = record
impl<'src> FirstPass<'src, ()> for weedle::PartialInterfaceMixinDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
record
.mixins
.entry(self.name.clone())
.or_insert_with(Default::default);
entry.partials.push(self);
.entry(self.identifier.0)
.or_insert_with(Default::default)
.push(&self.members.body);
Ok(())
}
}
impl FirstPass<()> for webidl::ast::Typedef {
fn first_pass<'a>(&'a self, record: &mut FirstPassRecord<'a>, (): ()) -> Result<()> {
if ::util::is_chrome_only(&self.extended_attributes) {
impl<'src> FirstPass<'src, ()> for weedle::TypedefDefinition<'src> {
fn first_pass(&'src self, record: &mut FirstPassRecord<'src>, (): ()) -> Result<()> {
if util::is_chrome_only(&self.attributes) {
return Ok(());
}
if record.typedefs.insert(self.name.clone(), *self.type_.clone()).is_some() {
warn!("Encountered multiple declarations of {}", self.name);
if record.typedefs.insert(self.identifier.0, &self.type_.type_).is_some() {
warn!("Encountered multiple declarations of {}", self.identifier.0);
}
Ok(())

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,37 +5,6 @@ controlling precisely how imports are imported and what they map to in JS. This
section is intended to hopefully be an exhaustive reference of the
possibilities!
* `module` and `version` - we've seen `module` so far indicating where we can
import items from but `version` is also allowed:
```rust
#[wasm_bindgen(module = "moment", version = "^2.0.0")]
extern {
type Moment;
fn moment() -> Moment;
#[wasm_bindgen(method)]
fn format(this: &Moment) -> String;
}
```
The `module` key is used to configure the module that each item is imported
from. The `version` key does not affect the generated wasm itself but rather
it's an informative directive for tools like [wasm-pack]. Tools like wasm-pack
will generate a `package.json` for you and the `version` listed here, when
`module` is also an NPM package, will correspond to what to write down in
`package.json`.
In other words the usage of `module` as the name of an NPM package and
`version` as the version requirement allows you to, inline in Rust, depend on
the NPM ecosystem and import functionality from those packages. When bundled
with a tool like [wasm-pack] everything will automatically get wired up with
bundlers and you should be good to go!
Note that the `version` is *required* if `module` doesn't start with `./`. If
`module` starts with `./` then it is an error to provide a version.
[wasm-pack]: https://github.com/rustwasm/wasm-pack
* `catch` - this attribute allows catching a JS exception. This can be attached
to any imported function and the function must return a `Result` where the
`Err` payload is a `JsValue`, like so:

73
package-lock.json generated
View File

@ -106,9 +106,9 @@
}
},
"@types/node": {
"version": "10.5.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.5.tgz",
"integrity": "sha512-6Qnb1gXbp3g1JX9QVJj3A6ORzc9XCyhokxUKaoonHgNXcQhmk8adhotxfkeK8El9TnFeUuH72yI6jQ5nDJKS6w==",
"version": "10.5.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.6.tgz",
"integrity": "sha512-c5Z1j1ysgo4878ptz6gxLcgMfJ6Wf908R3l5KAGabr0XJ72ZFmOCgsaodPpNYTfp4iOrSwgTDvR/BxbFfB4zPQ==",
"dev": true
},
"@webassemblyjs/ast": {
@ -1759,9 +1759,9 @@
"dev": true
},
"eslint": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.2.0.tgz",
"integrity": "sha512-zlggW1qp7/TBjwLfouRoY7eWXrXwJZFqCdIxxh0/LVB/QuuKuIMkzyUZEcDo6LBadsry5JcEMxIqd3H/66CXVg==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.3.0.tgz",
"integrity": "sha512-N/tCqlMKkyNvAvLu+zI9AqDasnSLt00K+Hu8kdsERliC9jYEc8ck12XtjvOXrBKu8fK6RrBcN9bat6Xk++9jAg==",
"dev": true,
"requires": {
"ajv": "^6.5.0",
@ -1795,7 +1795,7 @@
"path-is-inside": "^1.0.2",
"pluralize": "^7.0.0",
"progress": "^2.0.0",
"regexpp": "^1.1.0",
"regexpp": "^2.0.0",
"require-uncached": "^1.0.3",
"semver": "^5.5.0",
"string.prototype.matchall": "^2.0.0",
@ -2379,7 +2379,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@ -2400,12 +2401,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -2420,17 +2423,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -2547,7 +2553,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -2559,6 +2566,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -2573,6 +2581,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -2580,12 +2589,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@ -2604,6 +2615,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -2684,7 +2696,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -2696,6 +2709,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -2781,7 +2795,8 @@
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -2817,6 +2832,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -2836,6 +2852,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -2879,12 +2896,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@ -3225,9 +3244,9 @@
"dev": true
},
"ignore": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.2.tgz",
"integrity": "sha512-uoxnT7PYpyEnsja+yX+7v49B7LXxmzDJ2JALqHH3oEGzpM2U1IGcbfnOr8Dt57z3B/UWs7/iAgPFbmye8m4I0g==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.3.tgz",
"integrity": "sha512-Z/vAH2GGIEATQnBVXMclE2IGV6i0GyVngKThcGZ5kHgHMxLo9Ow2+XHRq1aEKEej5vOF1TPJNbvX6J/anT0M7A==",
"dev": true
},
"immediate": {
@ -5020,9 +5039,9 @@
}
},
"regexpp": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.0.tgz",
"integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA==",
"dev": true
},
"remove-trailing-separator": {
@ -6379,9 +6398,9 @@
}
},
"webpack": {
"version": "4.16.4",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.16.4.tgz",
"integrity": "sha512-RqUfwp4qMqv3oFwBQQOoK69C2tdu2FHJEqPABPqgjGDvOIOLqkTOhmmdJjpiRabzNAAH1ahmkA3z4xowlHN+VA==",
"version": "4.16.5",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.16.5.tgz",
"integrity": "sha512-i5cHYHonzSc1zBuwB5MSzW4v9cScZFbprkHK8ZgzPDCRkQXGGpYzPmJhbus5bOrZ0tXTcQp+xyImRSvKb0b+Kw==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.5.13",

View File

@ -8,14 +8,14 @@
"run-lint-generated-tests": "eslint ./target/generated-tests/*/out*js"
},
"devDependencies": {
"@types/node": "^10.5.5",
"@types/node": "^10.5.6",
"babel-eslint": "^8.2.6",
"eslint": "^5.2.0",
"eslint": "^5.3.0",
"geckodriver": "^1.12.1",
"selenium-webdriver": "^4.0.0-alpha.1",
"ts-loader": "^4.4.2",
"typescript": "^3.0.1",
"webpack": "^4.16.4",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5"
}

View File

@ -1,209 +0,0 @@
use super::project;
#[test]
fn dependencies_work() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
extern crate dependency;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn return_dep_ty(x: f64) -> dependency::Foo {
dependency::Foo(x)
}
#[wasm_bindgen]
pub fn takes_own_dep_ty(foo: dependency::Foo) -> f64 {
foo.0
}
#[wasm_bindgen]
pub fn takes_ref_dep_ty(foo: &dependency::Foo) -> f64 {
foo.0
}
#[wasm_bindgen]
pub fn takes_mut_dep_ty(foo: &mut dependency::Foo, x: f64) {
foo.0 = x;
}
"#,
)
.add_local_dependency("dependency", "vendor/dependency")
.file(
"vendor/dependency/Cargo.toml",
&format!(
r#"
[package]
name = "dependency"
version = "0.0.1"
authors = []
[dependencies]
wasm-bindgen = {{ path = '{}' }}
"#,
env!("CARGO_MANIFEST_DIR")
),
)
.file(
"vendor/dependency/src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct Foo(pub f64);
#[wasm_bindgen]
impl Foo {
pub fn new(x: f64) -> Foo { Foo(x) }
pub fn get(&self) -> f64 { self.0 }
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
const foo = wasm.return_dep_ty(42);
assert.strictEqual(foo.get(), 42);
const x = wasm.takes_ref_dep_ty(foo);
assert.strictEqual(x, 42);
const y = 1337;
wasm.takes_mut_dep_ty(foo, y);
assert.strictEqual(foo.get(), y);
const z = wasm.takes_own_dep_ty(foo);
assert.strictEqual(z, y);
assert.strictEqual(foo.ptr, 0);
}
"#,
)
.test();
}
#[test]
fn same_api_two_crates() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
extern crate a;
extern crate b;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "./foo")]
extern {
fn assert_next_undefined();
fn assert_next_ten();
}
#[wasm_bindgen]
pub fn test() {
assert_next_undefined();
a::test();
assert_next_ten();
b::test();
}
"#,
)
.file(
"foo.js",
r#"
import { strictEqual } from "assert";
let next = null;
export function assert_next_undefined() {
next = undefined;
}
export function assert_next_ten() {
next = 10;
}
export function foo(a) {
console.log(a, next);
strictEqual(a, next);
next = null;
}
"#,
)
.add_local_dependency("a", "a")
.file(
"a/Cargo.toml",
&format!(r#"
[package]
name = 'a'
version = '0.0.0'
[dependencies]
wasm-bindgen = {{ path = '{}' }}
"#,
env!("CARGO_MANIFEST_DIR")
),
)
.file(
"a/src/lib.rs",
"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = \"./foo\")]
extern {
fn foo();
}
pub fn test() {
foo();
}
",
)
.add_local_dependency("b", "b")
.file(
"b/Cargo.toml",
&format!(r#"
[package]
name = 'b'
version = '0.0.0'
[dependencies]
wasm-bindgen = {{ path = '{}' }}
"#,
env!("CARGO_MANIFEST_DIR")
),
)
.file(
"b/src/lib.rs",
"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = \"./foo\")]
extern {
fn foo(x: u32);
}
pub fn test() {
foo(10);
}
",
)
.test();
}

View File

@ -1,88 +0,0 @@
use super::project;
#[test]
fn unused_imports_not_generated() {
let mut project = project();
project
.debug(false)
.file("src/lib.rs", r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
pub fn foo();
}
#[wasm_bindgen]
pub fn run() {
}
"#)
.file("test.js", r#"
import { run } from "./out";
export function test() {
run();
}
"#)
.test();
let contents = project.read_js();
assert!(contents.contains("run"), "didn't find `run` in {}", contents);
assert!(!contents.contains("foo"), "found `foo` in {}", contents);
}
#[test]
fn versions() {
project()
.debug(false)
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "webpack", version = "^0.2.0")]
extern {
fn foo();
}
#[wasm_bindgen]
pub fn run() {
foo();
}
"#,
)
.file(
"test.js",
r#"
import * as fs from 'fs';
import * as assert from 'assert';
export function test() {
const bytes = fs.readFileSync('out_bg.wasm');
const m = new WebAssembly.Module(bytes);
const name = '__wasm_pack_unstable';
const sections = WebAssembly.Module.customSections(m, name);
assert.strictEqual(sections.length, 1);
const b = new Uint8Array(sections[0]);
const buf = new Buffer(b);
const map = JSON.parse(buf.toString());
assert.deepStrictEqual(map, {
version: '0.0.1',
modules: [
['webpack', '^0.2.0']
]
});
};
"#,
)
.test();
}

View File

@ -1,94 +0,0 @@
use super::project;
#[test]
fn serde() {
project()
.serde(true)
.depend("serde = '1.0'")
.depend("serde_derive = '1.0'")
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
#[macro_use]
extern crate serde_derive;
use wasm_bindgen::prelude::*;
#[derive(Deserialize, Serialize)]
pub struct Foo {
a: u32,
b: String,
c: Option<Bar>,
d: Bar,
}
#[derive(Deserialize, Serialize)]
pub struct Bar {
a: u32,
}
#[wasm_bindgen(module = "./test")]
extern {
fn verify(a: JsValue) -> JsValue;
}
#[wasm_bindgen]
pub fn run() {
let js = JsValue::from_serde("foo").unwrap();
assert_eq!(js.as_string(), Some("foo".to_string()));
let ret = verify(JsValue::from_serde(&Foo {
a: 0,
b: "foo".to_string(),
c: None,
d: Bar { a: 1 },
}).unwrap());
let foo = ret.into_serde::<Foo>().unwrap();
assert_eq!(foo.a, 2);
assert_eq!(foo.b, "bar");
assert!(foo.c.is_some());
assert_eq!(foo.c.as_ref().unwrap().a, 3);
assert_eq!(foo.d.a, 4);
}
#[wasm_bindgen]
pub fn parse(j: &JsValue) {
let s = j.into_serde::<String>().unwrap();
assert_eq!(s, "bar");
}
"#,
)
.file(
"test.js",
r#"
import { run, parse } from "./out";
import * as assert from "assert";
export function verify(a) {
assert.deepStrictEqual(a, {
a: 0,
b: 'foo',
c: null,
d: { a: 1 }
});
return {
a: 2,
b: 'bar',
c: { a: 3 },
d: { a: 4 },
}
}
export function test() {
run();
parse('bar');
}
"#,
)
.test();
}

View File

@ -2,14 +2,7 @@
extern crate wasm_bindgen_test_project_builder as project_builder;
use project_builder::{project, run};
use project_builder::project;
mod comments;
mod dependencies;
mod js_objects;
mod imports;
mod node;
mod non_debug;
mod non_wasm;
mod simple;
mod typescript;

View File

@ -1,161 +0,0 @@
use super::project;
#[test]
fn works() {
project()
.debug(false)
.nodejs_experimental_modules(false)
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "./test")]
extern {
static FOO: JsValue;
fn hit();
}
#[wasm_bindgen]
pub fn run() {
hit();
assert_eq!(FOO.as_f64(), Some(1.0));
}
#[wasm_bindgen]
pub struct Foo {
contents: u32,
}
#[wasm_bindgen]
impl Foo {
pub fn new() -> Foo {
Foo::with_contents(0)
}
pub fn with_contents(a: u32) -> Foo {
Foo { contents: a }
}
pub fn add(&mut self, amt: u32) -> u32 {
self.contents += amt;
self.contents
}
}
#[wasm_bindgen]
pub enum Color {
Green,
Yellow,
Red,
}
#[wasm_bindgen]
pub fn cycle(color: Color) -> Color {
match color {
Color::Green => Color::Yellow,
Color::Yellow => Color::Red,
Color::Red => Color::Green,
}
}
#[wasm_bindgen]
pub fn math(a: f32, b: f64) -> f64 {
b.acos() +
b.asin() +
b.atan() +
b.atan2(b) +
b.cbrt() +
b.cosh() +
b.exp_m1() +
b.ln_1p() +
b.sinh() +
b.tan() +
b.tanh() +
b.hypot(b) +
b.cos() +
b.exp() +
b.exp2() +
b.mul_add(b, b) +
b.ln() +
b.log(b) +
b.log10() +
b.log2() +
b.powi(8) +
b.powf(b) +
b.round() +
b.sin() +
b.abs() +
b.signum() +
b.floor() +
b.ceil() +
b.trunc() +
b.sqrt() +
(b % (a as f64)) +
((a.cos() +
a.exp() +
a.exp2() +
a.mul_add(a, a) +
a.ln() +
a.log(a) +
a.log10() +
a.log2() +
a.powi(8) +
a.powf(a) +
a.round() +
a.sin() +
a.abs() +
a.signum() +
a.floor() +
a.ceil() +
a.trunc() +
a.sqrt() +
(a % (b as f32))) as f64) +
(b + 2.0f64.powf(a as f64))
}
"#,
)
.file(
"test.js",
r#"
const assert = require('assert');
var called = false;
module.exports.hit = function() {
called = true;
};
module.exports.FOO = 1.0;
const { math, run, Foo, Color, cycle } = require('./out');
module.exports.test = function() {
run();
assert.strictEqual(called, true);
var r = Foo.new();
assert.strictEqual(r.add(0), 0);
assert.strictEqual(r.add(1), 1);
assert.strictEqual(r.add(2), 3);
r.free();
var r2 = Foo.with_contents(10);
assert.strictEqual(r2.add(0), 10);
assert.strictEqual(r2.add(1), 11);
assert.strictEqual(r2.add(2), 13);
r2.free();
assert.strictEqual(Color.Green, 0);
assert.strictEqual(Color.Yellow, 1);
assert.strictEqual(Color.Red, 2);
assert.strictEqual(Object.keys(Color).length, 3);
assert.strictEqual(cycle(Color.Green), Color.Yellow);
math(1.0, 2.0);
};
"#,
)
.test();
}

View File

@ -1,48 +0,0 @@
use super::project;
#[test]
fn works() {
project()
.debug(false)
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct A {}
#[wasm_bindgen]
impl A {
pub fn new() -> A {
A {}
}
}
#[wasm_bindgen]
pub fn clone(a: &JsValue) -> JsValue {
drop(a.clone());
a.clone()
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
let sym = Symbol('a');
assert.strictEqual(wasm.clone(sym), sym);
let a = wasm.A.new();
a.free();
}
"#,
)
.test();
}

View File

@ -1,101 +0,0 @@
use super::{project, run};
use std::process::Command;
#[test]
fn works() {
let mut p = project();
let name = p.crate_name();
p.rlib(true)
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct A {
x: u32,
}
#[wasm_bindgen]
impl A {
pub fn new() -> A {
A { x: 3 }
}
pub fn foo(&self) {
}
}
#[wasm_bindgen]
pub fn foo(x: bool) {
A::new().foo();
if x {
bar("test");
baz(JsValue::from(3));
}
}
#[wasm_bindgen]
extern {
fn some_import();
static A: JsValue;
}
#[wasm_bindgen]
pub fn bar(_: &str) -> JsValue {
some_import();
A.clone()
}
#[wasm_bindgen]
pub fn baz(_: JsValue) {
}
"#,
)
.file(
"tests/foo.rs",
&format!(
"
extern crate {} as mytest;
#[test]
fn foo() {{
mytest::foo(false);
mytest::A::new().foo();
}}
",
name
),
)
.file(
"benches/foo.rs",
&format!(
"
#![feature(test)]
extern crate test;
extern crate {} as mytest;
#[bench]
fn foo(b: &mut test::Bencher) {{
b.iter(|| mytest::foo(false));
}}
",
name
),
);
let (root, target_dir) = p.build();
let mut cmd = Command::new("cargo");
cmd.arg("test")
.arg("--test")
.arg("foo")
.arg("--bench")
.arg("foo")
.current_dir(&root)
.env("CARGO_TARGET_DIR", &target_dir);
run(&mut cmd, "cargo");
}

View File

@ -1,564 +0,0 @@
use super::project;
#[test]
fn add() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
a + b
}
#[wasm_bindgen]
pub fn add3(a: u32) -> u32 {
a + 3
}
#[wasm_bindgen]
pub fn get2(_b: bool) -> u32 {
2
}
#[wasm_bindgen]
pub fn return_and_take_bool(a: bool, b: bool) -> bool {
a && b
}
#[wasm_bindgen]
pub fn raw_pointers_work(a: *mut u32, b: *const u8) -> *const u32 {
unsafe {
(*a) = (*b) as u32;
return a
}
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
assert.strictEqual(wasm.add(1, 2), 3);
assert.strictEqual(wasm.add(2, 3), 5);
assert.strictEqual(wasm.add3(2), 5);
assert.strictEqual(wasm.get2(true), 2);
assert.strictEqual(wasm.return_and_take_bool(true, false), false);
}
"#,
)
.test();
}
#[test]
fn add_headless() {
project()
.headless(true)
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn add(a: u32, b: u32) -> u32 {
a + b
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
console.log("start `add_headless` test");
assert.strictEqual(wasm.add(1, 2), 3);
console.log("end `add_headless` test");
}
"#,
)
.test();
}
#[test]
fn string_arguments() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn assert_foo_and_bar(a: &str, b: &str) {
assert_eq!(a, "foo2");
assert_eq!(b, "bar");
}
#[wasm_bindgen]
pub fn assert_foo(a: &str) {
assert_eq!(a, "foo");
}
"#,
)
.file(
"test.js",
r#"
import * as wasm from "./out";
export function test() {
wasm.assert_foo("foo");
wasm.assert_foo_and_bar("foo2", "bar");
}
"#,
)
.test();
}
#[test]
fn return_a_string() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn clone(a: &str) -> String {
a.to_string()
}
#[wasm_bindgen]
pub fn concat(a: &str, b: &str, c: i8) -> String {
format!("{} {} {}", a, b, c)
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
assert.strictEqual(wasm.clone("foo"), "foo");
assert.strictEqual(wasm.clone("another"), "another");
assert.strictEqual(wasm.concat("a", "b", 3), "a b 3");
assert.strictEqual(wasm.concat("c", "d", -2), "c d -2");
}
"#,
)
.test();
}
#[test]
fn exceptions() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn foo(_a: u32) {}
#[wasm_bindgen]
pub fn bar(_a: &str) {}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
assert.throws(() => wasm.foo('a'), /expected a number argument/);
assert.throws(() => wasm.bar(3), /expected a string argument/);
}
"#,
)
.test();
}
// #[test]
// fn other_imports() {
// project()
// .file("src/lib.rs", r#"
// #![feature(use_extern_macros)]
//
// extern crate wasm_bindgen;
//
// use wasm_bindgen::prelude::*;
//
// extern {
// fn another_import(a: u32);
// }
//
// wasm_bindgen! {
// pub fn foo(a: u32) {
// unsafe { another_import(a); }
// }
// }
// "#)
// .file("test.js", r#"
// import * as assert from "assert";
// import * as wasm from "./out";
//
// let ARG: number | null = null;
//
// export function test() {
// wasm.foo(2);
// assert.strictEqual(ARG, 2);
// }
// "#)
// .test();
// }
#[test]
fn other_exports() {
project()
.file(
"src/lib.rs",
r#"
#[no_mangle]
pub extern fn foo(_a: u32) {
}
"#,
)
.file(
"test.js",
r#"
import * as wasm from "./out_bg";
export function test() {
wasm.foo(2);
}
"#,
)
.test();
}
#[test]
fn no_std() {
project()
.no_std(true)
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
#![no_std]
#![allow(dead_code)]
extern crate wasm_bindgen;
extern crate std as _some_other_name;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "./foo")]
extern {
fn test(a: &str);
type Js;
#[wasm_bindgen(constructor)]
fn new() -> Js;
#[wasm_bindgen(method)]
fn init(this: &Js);
}
#[wasm_bindgen]
pub fn foo(_a: u32) {}
"#,
)
.file(
"test.js",
r#"
import * as wasm from "./out_bg";
export function test() {
// mostly just testing the project compiles here
wasm.foo(1);
}
"#,
)
.file(
"foo.js",
r#"
export class Js {
init() {
}
}
"#,
)
.test();
}
#[test]
fn no_std_class() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
#![no_std]
#![allow(dead_code)]
extern crate wasm_bindgen;
extern crate std as _some_other_name;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn test(a: &str);
type Js;
#[wasm_bindgen(constructor)]
fn new() -> Js;
#[wasm_bindgen(method, structural)]
fn init(this: &Js);
}
#[wasm_bindgen]
pub fn foo(_a: u32) {}
#[wasm_bindgen]
pub struct A {}
#[wasm_bindgen]
impl A {
pub fn foo(&self) {}
pub fn bar(&mut self) {}
}
"#,
)
.file(
"test.js",
r#"
import * as wasm from "./out_bg";
export function test() {
// mostly just testing the project compiles here
wasm.foo(1);
}
"#,
)
.test();
}
#[test]
fn jsvalue_typeof() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn is_object(val: &JsValue) -> bool {
val.is_object()
}
#[wasm_bindgen]
pub fn is_function(val: &JsValue) -> bool {
val.is_function()
}
#[wasm_bindgen]
pub fn is_string(val: &JsValue) -> bool {
val.is_string()
}
"#,
)
.file(
"test.js",
r#"
import * as assert from "assert";
import * as wasm from "./out";
export function test() {
assert.ok(wasm.is_object({}));
assert.ok(!wasm.is_object(42));
assert.ok(wasm.is_function(function() {}));
assert.ok(!wasm.is_function(42));
assert.ok(wasm.is_string("2b or !2b"));
assert.ok(!wasm.is_string(42));
}
"#,
)
.test();
}
#[test]
fn binding_to_unimplemented_apis_doesnt_break_everything() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
#[derive(Clone)]
type Array;
#[wasm_bindgen(constructor)]
fn new() -> Array;
#[wasm_bindgen(method, catch)]
fn standardized_method_this_js_runtime_doesnt_implement_yet(this: &Array)
-> Result<(), JsValue>;
}
#[wasm_bindgen]
pub fn test() {
let array = Array::new();
let res = array.standardized_method_this_js_runtime_doesnt_implement_yet();
assert!(res.is_err());
}
"#,
)
.test();
}
#[test]
fn optional_slices() {
project()
.file(
"src/lib.rs",
r#"
#![feature(use_extern_macros, wasm_custom_section)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "./foo")]
extern {
fn optional_str_none(a: Option<&str>);
fn optional_str_some(a: Option<&str>);
fn optional_slice_none(a: Option<&[u8]>);
fn optional_slice_some(a: Option<&[u8]>);
fn optional_string_none(a: Option<String>);
fn optional_string_some(a: Option<String>);
fn optional_string_some_empty(a: Option<String>);
fn return_string_none() -> Option<String>;
fn return_string_some() -> Option<String>;
fn run_rust_tests();
}
#[wasm_bindgen]
pub fn test() {
optional_str_none(None);
optional_str_some(Some("x"));
optional_slice_none(None);
optional_slice_some(Some(&[1, 2, 3]));
optional_string_none(None);
optional_string_some_empty(Some(String::new()));
optional_string_some(Some("abcd".to_string()));
assert_eq!(return_string_none(), None);
assert_eq!(return_string_some(), Some("foo".to_string()));
run_rust_tests();
}
#[wasm_bindgen]
pub fn take_optional_str_none(x: Option<String>) {
assert!(x.is_none())
}
#[wasm_bindgen]
pub fn take_optional_str_some(x: Option<String>) {
assert_eq!(x, Some(String::from("hello")));
}
#[wasm_bindgen]
pub fn return_optional_str_none() -> Option<String> {
None
}
#[wasm_bindgen]
pub fn return_optional_str_some() -> Option<String> {
Some("world".to_string())
}
"#,
)
.file(
"foo.js",
r#"
import { strictEqual } from "assert";
import * as wasm from "./out";
export function optional_str_none(x) {
strictEqual(x, undefined);
}
export function optional_str_some(x) {
strictEqual(x, 'x');
}
export function optional_slice_none(x) {
strictEqual(x, undefined);
}
export function optional_slice_some(x) {
strictEqual(x.length, 3);
strictEqual(x[0], 1);
strictEqual(x[1], 2);
strictEqual(x[2], 3);
}
export function optional_string_none(x) {
strictEqual(x, undefined);
}
export function optional_string_some(x) {
strictEqual(x, 'abcd');
}
export function optional_string_some_empty(x) {
strictEqual(x, '');
}
export function return_string_none() {}
export function return_string_some() {
return 'foo';
}
export function run_rust_tests() {
wasm.take_optional_str_none();
wasm.take_optional_str_none(null);
wasm.take_optional_str_none(undefined);
wasm.take_optional_str_some('hello');
strictEqual(wasm.return_optional_str_none(), undefined);
strictEqual(wasm.return_optional_str_some(), 'world');
}
"#
)
.test();
}

View File

@ -0,0 +1,9 @@
[package]
name = "wasm-bindgen-test-crate-a"
version = "0.1.0"
authors = ["The wasm-bindgen Authors"]
license = "MIT/Apache-2.0"
description = "internal test crate for wasm-bindgen"
[dependencies]
wasm-bindgen = { path = '../../..', version = '0.2' }

14
tests/crates/a/src/lib.rs Normal file
View File

@ -0,0 +1,14 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js")]
extern {
fn foo();
}
pub fn test() {
foo();
}

View File

@ -0,0 +1,9 @@
[package]
name = "wasm-bindgen-test-crate-b"
version = "0.1.0"
authors = ["The wasm-bindgen Authors"]
license = "MIT/Apache-2.0"
description = "internal test crate for wasm-bindgen"
[dependencies]
wasm-bindgen = { path = '../../..', version = '0.2' }

14
tests/crates/b/src/lib.rs Normal file
View File

@ -0,0 +1,14 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js")]
extern {
fn foo(x: u32);
}
pub fn test() {
foo(10);
}

10
tests/no-std/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "no-std"
version = "0.1.0"
authors = ["The wasm-bindgen Developers"]
[lib]
path = "test.rs"
[dependencies]
wasm-bindgen = { path = '../..', default-features = false }

0
tests/no-std/lib.rs Normal file
View File

28
tests/no-std/test.rs Normal file
View File

@ -0,0 +1,28 @@
//! This is a test that we compile `wasm-bindgen` itself in `no_std` mode and we
//! can export/import various items.
//!
//! This doesn't actually run any tests, it's mostly a compile-time verification
//! that things work.
#![feature(use_extern_macros)]
#![no_std]
#![allow(dead_code)]
extern crate wasm_bindgen;
extern crate std as _some_other_name;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn foo(_a: u32) {}
#[wasm_bindgen]
extern {
fn test(a: &str);
type Js;
#[wasm_bindgen(constructor)]
fn new() -> Js;
#[wasm_bindgen(method, structural)]
fn init(this: &Js);
}

53
tests/non_wasm.rs Normal file
View File

@ -0,0 +1,53 @@
#![feature(use_extern_macros)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct A {
x: u32,
}
#[wasm_bindgen]
impl A {
pub fn new() -> A {
A { x: 3 }
}
pub fn foo(&self) {
drop(self.x);
}
}
#[wasm_bindgen]
pub fn foo(x: bool) {
A::new().foo();
if x {
bar("test");
baz(JsValue::from(3));
}
}
#[wasm_bindgen]
extern {
fn some_import();
static A: JsValue;
}
#[wasm_bindgen]
pub fn bar(_: &str) -> JsValue {
some_import();
A.clone()
}
#[wasm_bindgen]
pub fn baz(_: JsValue) {
}
#[test]
fn test_foo() {
foo(false);
A::new().foo();
}

View File

@ -0,0 +1,30 @@
//! This is a test that we can define items in a `#![no_std]` crate when
//! `wasm-bindgen` is compiled itself with the `std` feature and everything
//! works out just fine.
#![feature(use_extern_macros)]
#![no_std]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern {
fn test(a: &str);
type Js;
#[wasm_bindgen(constructor)]
fn new() -> Js;
#[wasm_bindgen(method, structural)]
fn init(this: &Js);
}
#[wasm_bindgen]
pub struct A {}
#[wasm_bindgen]
impl A {
pub fn foo(&self) {}
pub fn bar(&mut self) {}
}

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/api.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/api.js")]
extern {
fn js_works();
fn js_eq_works();

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/char.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/char.js")]
extern {
fn js_identity(c: char) -> char;
fn js_works();

View File

@ -31,6 +31,10 @@ exports.js_strings = () => {
};
exports.js_exceptions = () => {
// this test only works when `--debug` is passed to `wasm-bindgen` (or the
// equivalent thereof)
if (require('process').env.WASM_BINDGEN_NO_DEBUG)
return;
assert.throws(() => new wasm.ClassesExceptions1(), /cannot invoke `new` directly/);
let a = wasm.ClassesExceptions1.new();
a.free();

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/classes.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/classes.js")]
extern {
fn js_simple();
fn js_strings();

View File

@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*;
use std::cell::Cell;
use std::rc::Rc;
#[wasm_bindgen(module = "tests/wasm/closures.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/closures.js")]
extern {
fn works_call(a: &Fn());
fn works_thread(a: &Fn(u32) -> u32) -> u32;

View File

@ -0,0 +1,17 @@
const assert = require('assert');
let next = null;
exports.assert_next_undefined = function() {
next = undefined;
};
exports.assert_next_ten = function() {
next = 10;
};
exports.foo = function(a) {
console.log(a, next);
assert.strictEqual(a, next);
next = null;
};

View File

@ -0,0 +1,18 @@
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use wasm_bindgen_test_crate_a as a;
use wasm_bindgen_test_crate_b as b;
#[wasm_bindgen(module = "tests/wasm/duplicate_deps.js")]
extern {
fn assert_next_undefined();
fn assert_next_ten();
}
#[wasm_bindgen_test]
fn works() {
assert_next_undefined();
a::test();
assert_next_ten();
b::test();
}

View File

@ -3,7 +3,7 @@ use wasm_bindgen_test::*;
pub mod same_function_different_locations_a {
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/duplicates_a.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/duplicates_a.js")]
extern {
pub fn foo();
}
@ -12,7 +12,7 @@ pub mod same_function_different_locations_a {
pub mod same_function_different_locations_b {
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/duplicates_a.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/duplicates_a.js")]
extern {
pub fn foo();
}
@ -27,7 +27,7 @@ fn same_function_different_locations() {
pub mod same_function_different_modules_a {
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/duplicates_b.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/duplicates_b.js")]
extern {
pub fn foo() -> bool;
}
@ -36,7 +36,7 @@ pub mod same_function_different_modules_a {
pub mod same_function_different_modules_b {
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/duplicates_c.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/duplicates_c.js")]
extern {
pub fn foo() -> bool;
}

View File

@ -2,7 +2,7 @@ use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
use self::inner::ColorWithCustomValues;
#[wasm_bindgen(module = "tests/wasm/enums.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/enums.js")]
extern {
fn js_c_style_enum();
fn js_c_style_enum_with_custom_values();

View File

@ -5,7 +5,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/import_class.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/import_class.js")]
extern {
fn math_log(f: f64) -> f64;

View File

@ -1,5 +1,6 @@
const assert = require('assert');
const wasm = require('wasm-bindgen-test');
const fs = require('fs');
let ARG = null;
let ANOTHER_ARG = null;
@ -90,3 +91,12 @@ exports.touch_custom_type = function() {
exports.interpret_2_as_custom_type = function() {
assert.throws(wasm.interpret_2_as_custom_type, /expected value of type CustomType/);
};
exports.baz$ = function() {};
exports.$foo = 1.0;
exports.assert_dead_import_not_generated = function() {
const filename = require.resolve("wasm-bindgen-test");
const bindings = fs.readFileSync(filename);
assert.ok(!bindings.includes("unused_import"));
};

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/imports.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/imports.js")]
extern {
fn test_simple();
@ -42,6 +42,14 @@ extern {
fn custom_type_return_2() -> CustomType;
#[wasm_bindgen(js_name = interpret_2_as_custom_type)]
fn js_interpret_2_as_custom_type();
#[wasm_bindgen(js_name = "baz$")]
fn renamed_with_dollar_sign();
#[wasm_bindgen(js_name = "$foo")]
static RENAMED: JsValue;
fn unused_import();
fn assert_dead_import_not_generated();
}
#[wasm_bindgen]
@ -153,3 +161,18 @@ impl CustomType {
}
}
#[wasm_bindgen_test]
fn rename_with_string() {
renamed_with_dollar_sign();
}
#[wasm_bindgen_test]
fn rename_static_with_string() {
assert_eq!(RENAMED.as_f64(), Some(1.0));
}
#[wasm_bindgen_test]
fn dead_imports_not_generated() {
assert_dead_import_not_generated();
}

View File

@ -82,3 +82,19 @@ exports.js_returning_vector = () => {
exports.js_another_vector_return = () => {
assert.deepStrictEqual(wasm.another_vector_return_get_array(), [1, 2, 3, 4, 5, 6]);
};
exports.verify_serde = function(a) {
assert.deepStrictEqual(a, {
a: 0,
b: 'foo',
c: null,
d: { a: 1 }
});
return {
a: 2,
b: 'bar',
c: { a: 3 },
d: { a: 4 },
}
};

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/js_objects.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/js_objects.js")]
extern {
fn simple_foo(s: &JsValue);
fn js_simple();
@ -26,6 +26,7 @@ extern {
fn js_returning_vector();
fn js_another_vector_return();
fn verify_serde(val: JsValue) -> JsValue;
}
#[wasm_bindgen]
@ -105,3 +106,40 @@ pub fn another_vector_return_get_array() -> Vec<JsValue> {
fn another_vector_return() {
js_another_vector_return();
}
#[cfg(feature = "serde-serialize")]
#[wasm_bindgen_test]
fn serde() {
#[derive(Deserialize, Serialize)]
pub struct Foo {
a: u32,
b: String,
c: Option<Bar>,
d: Bar,
}
#[derive(Deserialize, Serialize)]
pub struct Bar {
a: u32,
}
let js = JsValue::from_serde("foo").unwrap();
assert_eq!(js.as_string(), Some("foo".to_string()));
let ret = verify_serde(JsValue::from_serde(&Foo {
a: 0,
b: "foo".to_string(),
c: None,
d: Bar { a: 1 },
}).unwrap());
let foo = ret.into_serde::<Foo>().unwrap();
assert_eq!(foo.a, 2);
assert_eq!(foo.b, "bar");
assert!(foo.c.is_some());
assert_eq!(foo.c.as_ref().unwrap().a, 3);
assert_eq!(foo.d.a, 4);
assert_eq!(JsValue::from("bar").into_serde::<String>().unwrap(), "bar");
}

View File

@ -3,19 +3,28 @@
extern crate wasm_bindgen_test;
extern crate wasm_bindgen;
extern crate wasm_bindgen_test_crate_a;
extern crate wasm_bindgen_test_crate_b;
#[cfg(feature = "serde-serialize")]
#[macro_use]
extern crate serde_derive;
pub mod api;
pub mod char;
pub mod classes;
pub mod closures;
pub mod duplicate_deps;
pub mod duplicates;
pub mod enums;
pub mod imports;
pub mod import_class;
pub mod imports;
pub mod js_objects;
pub mod math;
pub mod node;
pub mod option;
pub mod optional_primitives;
pub mod simple;
pub mod slice;
pub mod structural;
pub mod u64;

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/math.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/math.js")]
extern {
fn js_auto_bind_math();
}
@ -64,4 +64,4 @@ pub fn math(a: f32, b: f64) -> f64 {
#[wasm_bindgen_test]
fn auto_bind_math() {
js_auto_bind_math();
}
}

34
tests/wasm/node.js Normal file
View File

@ -0,0 +1,34 @@
const assert = require('assert');
const wasm = require('wasm-bindgen-test');
var called = false;
exports.hit = function() {
called = true;
};
exports.FOO = 1.0;
exports.test_works = function() {
assert.strictEqual(called, true);
var r = wasm.Foo.new();
assert.strictEqual(r.add(0), 0);
assert.strictEqual(r.add(1), 1);
assert.strictEqual(r.add(2), 3);
r.free();
var r2 = wasm.Foo.with_contents(10);
assert.strictEqual(r2.add(0), 10);
assert.strictEqual(r2.add(1), 11);
assert.strictEqual(r2.add(2), 13);
r2.free();
assert.strictEqual(wasm.Color.Green, 0);
assert.strictEqual(wasm.Color.Yellow, 1);
assert.strictEqual(wasm.Color.Red, 2);
assert.strictEqual(Object.keys(wasm.Color).length, 3);
assert.strictEqual(wasm.cycle(wasm.Color.Green), wasm.Color.Yellow);
wasm.node_math(1.0, 2.0);
};

105
tests/wasm/node.rs Normal file
View File

@ -0,0 +1,105 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/node.js")]
extern {
fn test_works();
static FOO: JsValue;
fn hit();
}
#[wasm_bindgen_test]
fn works() {
hit();
assert_eq!(FOO.as_f64(), Some(1.0));
test_works();
}
#[wasm_bindgen]
pub struct Foo {
contents: u32,
}
#[wasm_bindgen]
impl Foo {
pub fn new() -> Foo {
Foo::with_contents(0)
}
pub fn with_contents(a: u32) -> Foo {
Foo { contents: a }
}
pub fn add(&mut self, amt: u32) -> u32 {
self.contents += amt;
self.contents
}
}
#[wasm_bindgen]
pub enum Color {
Green,
Yellow,
Red,
}
#[wasm_bindgen]
pub fn cycle(color: Color) -> Color {
match color {
Color::Green => Color::Yellow,
Color::Yellow => Color::Red,
Color::Red => Color::Green,
}
}
#[wasm_bindgen]
pub fn node_math(a: f32, b: f64) -> f64 {
b.acos() +
b.asin() +
b.atan() +
b.atan2(b) +
b.cbrt() +
b.cosh() +
b.exp_m1() +
b.ln_1p() +
b.sinh() +
b.tan() +
b.tanh() +
b.hypot(b) +
b.cos() +
b.exp() +
b.exp2() +
b.mul_add(b, b) +
b.ln() +
b.log(b) +
b.log10() +
b.log2() +
b.powi(8) +
b.powf(b) +
b.round() +
b.sin() +
b.abs() +
b.signum() +
b.floor() +
b.ceil() +
b.trunc() +
b.sqrt() +
(b % (a as f64)) +
((a.cos() +
a.exp() +
a.exp2() +
a.mul_add(a, a) +
a.ln() +
a.log(a) +
a.log10() +
a.log2() +
a.powi(8) +
a.powf(a) +
a.round() +
a.sin() +
a.abs() +
a.signum() +
a.floor() +
a.ceil() +
a.trunc() +
a.sqrt() +
(a % (b as f32))) as f64) +
(b + 2.0f64.powf(a as f64))
}

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/option.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/option.js")]
extern {
pub type MyType;
#[wasm_bindgen(constructor)]

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/optional_primitives.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/optional_primitives.js")]
extern {
fn optional_i32_js_identity(a: Option<i32>) -> Option<i32>;
fn optional_u32_js_identity(a: Option<u32>) -> Option<u32>;

89
tests/wasm/simple.js Normal file
View File

@ -0,0 +1,89 @@
const assert = require('assert');
const wasm = require('wasm-bindgen-test');
exports.test_add = function() {
assert.strictEqual(wasm.simple_add(1, 2), 3);
assert.strictEqual(wasm.simple_add(2, 3), 5);
assert.strictEqual(wasm.simple_add3(2), 5);
assert.strictEqual(wasm.simple_get2(true), 2);
assert.strictEqual(wasm.simple_return_and_take_bool(true, false), false);
};
exports.test_string_arguments = function() {
wasm.simple_assert_foo("foo");
wasm.simple_assert_foo_and_bar("foo2", "bar");
};
exports.test_return_a_string = function() {
assert.strictEqual(wasm.simple_clone("foo"), "foo");
assert.strictEqual(wasm.simple_clone("another"), "another");
assert.strictEqual(wasm.simple_concat("a", "b", 3), "a b 3");
assert.strictEqual(wasm.simple_concat("c", "d", -2), "c d -2");
};
exports.test_wrong_types = function() {
// this test only works when `--debug` is passed to `wasm-bindgen` (or the
// equivalent thereof)
if (require('process').env.WASM_BINDGEN_NO_DEBUG)
return;
assert.throws(() => wasm.simple_int('a'), /expected a number argument/);
assert.throws(() => wasm.simple_str(3), /expected a string argument/);
};
exports.test_other_exports_still_available = function() {
require('wasm-bindgen-test_bg').foo(3);
};
exports.test_jsvalue_typeof = function() {
assert.ok(wasm.is_object({}));
assert.ok(!wasm.is_object(42));
assert.ok(wasm.is_function(function() {}));
assert.ok(!wasm.is_function(42));
assert.ok(wasm.is_string("2b or !2b"));
assert.ok(!wasm.is_string(42));
};
exports.optional_str_none = function(x) {
assert.strictEqual(x, undefined);
};
exports.optional_str_some = function(x) {
assert.strictEqual(x, 'x');
};
exports.optional_slice_none = function(x) {
assert.strictEqual(x, undefined);
};
exports.optional_slice_some = function(x) {
assert.strictEqual(x.length, 3);
assert.strictEqual(x[0], 1);
assert.strictEqual(x[1], 2);
assert.strictEqual(x[2], 3);
}
exports.optional_string_none = function(x) {
assert.strictEqual(x, undefined);
};
exports.optional_string_some = function(x) {
assert.strictEqual(x, 'abcd');
};
exports.optional_string_some_empty = function(x) {
assert.strictEqual(x, '');
};
exports.return_string_none = function() {};
exports.return_string_some = function() {
return 'foo';
};
exports.test_rust_optional = function() {
wasm.take_optional_str_none();
wasm.take_optional_str_none(null);
wasm.take_optional_str_none(undefined);
wasm.take_optional_str_some('hello');
assert.strictEqual(wasm.return_optional_str_none(), undefined);
assert.strictEqual(wasm.return_optional_str_some(), 'world');
};

180
tests/wasm/simple.rs Normal file
View File

@ -0,0 +1,180 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/simple.js")]
extern {
fn test_add();
fn test_string_arguments();
fn test_return_a_string();
fn test_wrong_types();
fn test_other_exports_still_available();
fn test_jsvalue_typeof();
fn optional_str_none(a: Option<&str>);
fn optional_str_some(a: Option<&str>);
fn optional_slice_none(a: Option<&[u8]>);
fn optional_slice_some(a: Option<&[u8]>);
fn optional_string_none(a: Option<String>);
fn optional_string_some(a: Option<String>);
fn optional_string_some_empty(a: Option<String>);
fn return_string_none() -> Option<String>;
fn return_string_some() -> Option<String>;
fn test_rust_optional();
}
#[wasm_bindgen_test]
fn add() {
test_add();
}
#[wasm_bindgen]
pub fn simple_add(a: u32, b: u32) -> u32 {
a + b
}
#[wasm_bindgen]
pub fn simple_add3(a: u32) -> u32 {
a + 3
}
#[wasm_bindgen]
pub fn simple_get2(_b: bool) -> u32 {
2
}
#[wasm_bindgen]
pub fn simple_return_and_take_bool(a: bool, b: bool) -> bool {
a && b
}
#[wasm_bindgen]
pub fn simple_raw_pointers_work(a: *mut u32, b: *const u8) -> *const u32 {
unsafe {
(*a) = (*b) as u32;
return a
}
}
#[wasm_bindgen_test]
fn string_arguments() {
test_string_arguments();
}
#[wasm_bindgen]
pub fn simple_assert_foo_and_bar(a: &str, b: &str) {
assert_eq!(a, "foo2");
assert_eq!(b, "bar");
}
#[wasm_bindgen]
pub fn simple_assert_foo(a: &str) {
assert_eq!(a, "foo");
}
#[wasm_bindgen_test]
fn return_a_string() {
test_return_a_string();
}
#[wasm_bindgen]
pub fn simple_clone(a: &str) -> String {
a.to_string()
}
#[wasm_bindgen]
pub fn simple_concat(a: &str, b: &str, c: i8) -> String {
format!("{} {} {}", a, b, c)
}
#[wasm_bindgen_test]
fn wrong_types() {
test_wrong_types();
}
#[wasm_bindgen]
pub fn simple_int(_a: u32) {}
#[wasm_bindgen]
pub fn simple_str(_a: &str) {}
#[wasm_bindgen_test]
fn other_exports() {
test_other_exports_still_available();
}
#[no_mangle]
pub extern fn foo(_a: u32) {
}
#[wasm_bindgen_test]
fn jsvalue_typeof() {
test_jsvalue_typeof();
}
#[wasm_bindgen]
pub fn is_object(val: &JsValue) -> bool {
val.is_object()
}
#[wasm_bindgen]
pub fn is_function(val: &JsValue) -> bool {
val.is_function()
}
#[wasm_bindgen]
pub fn is_string(val: &JsValue) -> bool {
val.is_string()
}
#[wasm_bindgen]
extern {
#[derive(Clone)]
type Array;
#[wasm_bindgen(constructor)]
fn new() -> Array;
#[wasm_bindgen(method, catch)]
fn standardized_method_this_js_runtime_doesnt_implement_yet(this: &Array)
-> Result<(), JsValue>;
}
#[wasm_bindgen_test]
fn binding_to_unimplemented_apis_doesnt_break_everything() {
let array = Array::new();
let res = array.standardized_method_this_js_runtime_doesnt_implement_yet();
assert!(res.is_err());
}
#[wasm_bindgen_test]
fn optional_slices() {
optional_str_none(None);
optional_str_some(Some("x"));
optional_slice_none(None);
optional_slice_some(Some(&[1, 2, 3]));
optional_string_none(None);
optional_string_some_empty(Some(String::new()));
optional_string_some(Some("abcd".to_string()));
assert_eq!(return_string_none(), None);
assert_eq!(return_string_some(), Some("foo".to_string()));
test_rust_optional();
}
#[wasm_bindgen]
pub fn take_optional_str_none(x: Option<String>) {
assert!(x.is_none())
}
#[wasm_bindgen]
pub fn take_optional_str_some(x: Option<String>) {
assert_eq!(x, Some(String::from("hello")));
}
#[wasm_bindgen]
pub fn return_optional_str_none() -> Option<String> {
None
}
#[wasm_bindgen]
pub fn return_optional_str_some() -> Option<String> {
Some("world".to_string())
}

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/slice.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/slice.js")]
extern {
fn js_export();
@ -44,7 +44,7 @@ fn export() {
macro_rules! import_macro {
($(($rust:ident, $js:ident, $i:ident))*) => ($(
#[wasm_bindgen(module = "tests/wasm/slice.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/slice.js")]
extern {
fn $js(a: &[$i]) -> Vec<$i>;
}
@ -105,7 +105,7 @@ fn pass_array() {
macro_rules! import_mut_macro {
($(($rust:ident, $js:ident, $i:ident))*) => (
$(
#[wasm_bindgen(module = "tests/wasm/slice.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/slice.js")]
extern {
fn $js(a: &mut [$i]);
}

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/structural.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/structural.js")]
extern {
fn js_works();
}

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/u64.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/u64.js")]
extern {
fn i64_js_identity(a: i64) -> i64;
fn u64_js_identity(a: u64) -> u64;

View File

@ -1,7 +1,7 @@
use wasm_bindgen_test::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "tests/wasm/validate_prt.js", version = "*")]
#[wasm_bindgen(module = "tests/wasm/validate_prt.js")]
extern {
fn js_works();
}

View File

@ -78,9 +78,9 @@
lodash "^4.2.0"
to-fast-properties "^2.0.0"
"@types/node@^10.5.5":
version "10.5.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.5.tgz#8e84d24e896cd77b0d4f73df274027e3149ec2ba"
"@types/node@^10.5.6":
version "10.5.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.5.6.tgz#1640f021dd0eaf12e731e54198c12ad2e020dc8e"
"@webassemblyjs/ast@1.5.13":
version "1.5.13"
@ -245,9 +245,9 @@ acorn@^5.0.0, acorn@^5.0.3, acorn@^5.6.0, acorn@^5.6.2:
version "5.7.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
adm-zip@0.4.7:
version "0.4.7"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1"
adm-zip@0.4.11:
version "0.4.11"
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.11.tgz#2aa54c84c4b01a9d0fb89bb11982a51f13e3d62a"
ajv-keywords@^3.0.0, ajv-keywords@^3.1.0:
version "3.2.0"
@ -1267,9 +1267,9 @@ eslint-visitor-keys@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
eslint@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.2.0.tgz#3901ae249195d473e633c4acbc370068b1c964dc"
eslint@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.3.0.tgz#53695aca5213968aacdf970ccb231e42a2b285f8"
dependencies:
ajv "^6.5.0"
babel-code-frame "^6.26.0"
@ -1302,7 +1302,7 @@ eslint@^5.2.0:
path-is-inside "^1.0.2"
pluralize "^7.0.0"
progress "^2.0.0"
regexpp "^1.1.0"
regexpp "^2.0.0"
require-uncached "^1.0.3"
semver "^5.5.0"
string.prototype.matchall "^2.0.0"
@ -1651,11 +1651,11 @@ gauge@~2.7.3:
strip-ansi "^3.0.1"
wide-align "^1.1.0"
geckodriver@^1.12.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.12.0.tgz#997a1efeca90543192fbcf1eae70d7cb2196330e"
geckodriver@^1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.12.1.tgz#f3b2ecd5224f383462f07841f4fdcf5007d1b42d"
dependencies:
adm-zip "0.4.7"
adm-zip "0.4.11"
bluebird "3.4.6"
got "5.6.0"
tar "4.0.2"
@ -3271,9 +3271,9 @@ regexp.prototype.flags@^1.2.0:
dependencies:
define-properties "^1.1.2"
regexpp@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab"
regexpp@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365"
remove-trailing-separator@^1.0.1:
version "1.1.0"
@ -4185,9 +4185,9 @@ webpack-sources@^1.0.1, webpack-sources@^1.1.0:
source-list-map "^2.0.0"
source-map "~0.6.1"
webpack@^4.16.4:
version "4.16.4"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.4.tgz#6b020f76483bc66339164c296d89978aa100d37a"
webpack@^4.16.5:
version "4.16.5"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.5.tgz#29fb39462823d7eb8aefcab8b45f7f241db0d092"
dependencies:
"@webassemblyjs/ast" "1.5.13"
"@webassemblyjs/helper-module-context" "1.5.13"