From 0320bc0d7c886700d2fbb5ddb0a391a8a76782dc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 5 Feb 2018 16:39:11 -0800 Subject: [PATCH] more-wip --- crates/wasm-bindgen-cli-support/src/js.rs | 62 +++++++++++++-- crates/wasm-bindgen-macro/src/ast.rs | 2 +- crates/wasm-bindgen-macro/src/lib.rs | 17 ++-- crates/wasm-bindgen-shared/src/lib.rs | 7 ++ tests/import-class.rs | 94 +++++++++++++++++++++++ 5 files changed, 163 insertions(+), 19 deletions(-) diff --git a/crates/wasm-bindgen-cli-support/src/js.rs b/crates/wasm-bindgen-cli-support/src/js.rs index 5336add8..21af91d1 100644 --- a/crates/wasm-bindgen-cli-support/src/js.rs +++ b/crates/wasm-bindgen-cli-support/src/js.rs @@ -26,6 +26,9 @@ impl<'a> Js<'a> { for s in self.program.structs.iter() { self.generate_struct(s); } + for s in self.program.imported_structs.iter() { + self.generate_import_struct(s); + } { let mut bind = |name: &str, f: &Fn(&mut Self) -> String| { @@ -467,15 +470,56 @@ impl<'a> Js<'a> { } pub fn generate_import(&mut self, module: &str, import: &shared::Function) { - let mut dst = String::new(); - let imported_name = format!("import{}", self.imports.len()); self.imports.push_str(&format!(" import {{ {} as {} }} from '{}'; ", import.name, imported_name, module)); - dst.push_str(&format!("function __wbg_import_{}(", import.name)); + self.gen_import_shim(&import.mangled_import_name(None), + &imported_name, + import) + } + + pub fn generate_import_struct(&mut self, import: &shared::ImportStruct) { + if let Some(ref module) = import.module { + self.imports.push_str(&format!(" + import {{ {} }} from '{}'; + ", import.name, module)); + } + + for &(method, ref function) in import.functions.iter() { + self.generate_import_struct_function(&import.name, + method, + function); + } + } + + fn generate_import_struct_function( + &mut self, + class: &str, + is_method: bool, + function: &shared::Function, + ) { + let delegate = if is_method { + format!("{}.prototype.{}.call", class, function.name) + } else { + format!("{}.{}", class, function.name) + }; + self.gen_import_shim(&function.mangled_import_name(Some(class)), + &delegate, + function) + } + + fn gen_import_shim( + &mut self, + shim_name: &str, + shim_delegate: &str, + import: &shared::Function, + ) { + let mut dst = String::new(); + + dst.push_str(&format!("function {}(", shim_name)); let mut invocation = String::new(); for (i, arg) in import.arguments.iter().enumerate() { @@ -518,7 +562,7 @@ impl<'a> Js<'a> { } } dst.push_str(")"); - let invoc = format!("{}({})", imported_name, invocation); + let invoc = format!("{}({})", shim_delegate, invocation); let invoc = match import.ret { Some(shared::Type::Number) => invoc, Some(shared::Type::Boolean) => format!("{} ? 1 : 0", invoc), @@ -571,12 +615,16 @@ impl<'a> Js<'a> { // fixed upstream. let program_import = self.program.imports .iter() - .find(|&&(_, ref f)| f.name == import.field()); - if program_import.is_some() { + .any(|&(_, ref f)| f.mangled_import_name(None) == import.field()); + let struct_import = self.program.imported_structs + .iter() + .flat_map(|s| s.functions.iter().map(move |f| (s, &f.1))) + .any(|(s, f)| f.mangled_import_name(Some(&s.name)) == import.field()); + if program_import || struct_import { import.module_mut().truncate(0); import.module_mut().push_str("./"); import.module_mut().push_str(module_name); - import.field_mut().insert_str(0, "__wbg_import_"); + continue } } } diff --git a/crates/wasm-bindgen-macro/src/ast.rs b/crates/wasm-bindgen-macro/src/ast.rs index dddb8570..091c06cc 100644 --- a/crates/wasm-bindgen-macro/src/ast.rs +++ b/crates/wasm-bindgen-macro/src/ast.rs @@ -256,7 +256,7 @@ impl Function { syn::Ident::from(generated_name) } - fn shared(&self) -> shared::Function { + pub fn shared(&self) -> shared::Function { shared::Function { name: self.name.as_ref().to_string(), arguments: self.arguments.iter().map(|t| t.shared()).collect(), diff --git a/crates/wasm-bindgen-macro/src/lib.rs b/crates/wasm-bindgen-macro/src/lib.rs index a7a26953..4ab85a79 100644 --- a/crates/wasm-bindgen-macro/src/lib.rs +++ b/crates/wasm-bindgen-macro/src/lib.rs @@ -429,10 +429,9 @@ impl ToTokens for Receiver { } fn bindgen_import(import: &ast::Import, tokens: &mut Tokens) { - bindgen_import_function(&import.function, - &import.function.ident.to_string(), - Some(&import.module), - tokens); + let import_name = import.function.wasm_function.shared() + .mangled_import_name(None); + bindgen_import_function(&import.function, &import_name, tokens); } fn bindgen_imported_struct(import: &ast::ImportStruct, tokens: &mut Tokens) { @@ -446,12 +445,9 @@ fn bindgen_imported_struct(import: &ast::ImportStruct, tokens: &mut Tokens) { let mut methods = Tokens::new(); for &(_is_method, ref f) in import.functions.iter() { - let import_name = format!("__wbg_{}_{}", name, f.ident); - - bindgen_import_function(f, - &import_name, - import.module.as_ref().map(|s| &**s), - &mut methods); + let import_name = f.wasm_function.shared() + .mangled_import_name(Some(&import.name.to_string())); + bindgen_import_function(f, &import_name, &mut methods); } (my_quote! { @@ -463,7 +459,6 @@ fn bindgen_imported_struct(import: &ast::ImportStruct, tokens: &mut Tokens) { fn bindgen_import_function(import: &ast::ImportFunction, import_name: &str, - _import_module: Option<&str>, tokens: &mut Tokens) { let vis = &import.rust_vis; let ret = &import.rust_decl.output; diff --git a/crates/wasm-bindgen-shared/src/lib.rs b/crates/wasm-bindgen-shared/src/lib.rs index 38aa1cd4..4c5c4aa4 100644 --- a/crates/wasm-bindgen-shared/src/lib.rs +++ b/crates/wasm-bindgen-shared/src/lib.rs @@ -61,6 +61,13 @@ impl Function { name.push_str(&self.name); return name } + + pub fn mangled_import_name(&self, struct_: Option<&str>) -> String { + match struct_ { + Some(s) => format!("__wbg_s_{}_{}", s, self.name), + None => format!("__wbg_f_{}", self.name), + } + } } #[derive(Serialize, Deserialize)] diff --git a/tests/import-class.rs b/tests/import-class.rs index a23b174b..eed7b06c 100644 --- a/tests/import-class.rs +++ b/tests/import-class.rs @@ -13,18 +13,112 @@ fn simple() { wasm_bindgen! { extern struct Math { fn random() -> f64; + fn log(a: f64) -> f64; } pub fn get_random() -> f64 { Math::random() } + + pub fn do_log(a: f64) -> f64 { + Math::log(a) + } } "#) .file("test.ts", r#" import * as wasm from "./out"; + import * as assert from "assert"; export function test() { wasm.get_random(); + assert.strictEqual(wasm.do_log(1.0), Math.log(1.0)); + } + "#) + .test(); +} + +#[test] +fn import_class() { + test_support::project() + .file("src/lib.rs", r#" + #![feature(proc_macro)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + wasm_bindgen! { + #[wasm_module = "./test"] + extern struct Foo { + fn bar(); + } + + pub fn bar() { + Foo::bar(); + } + } + "#) + .file("test.ts", r#" + import * as wasm from "./out"; + import * as assert from "assert"; + + let called = false; + + export class Foo { + static bar() { + called = true; + } + } + + export function test() { + wasm.bar(); + assert.strictEqual(called, true); + } + "#) + .test(); +} + +#[test] +fn construct() { + test_support::project() + .file("src/lib.rs", r#" + #![feature(proc_macro)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + wasm_bindgen! { + #[wasm_module = "./test"] + extern struct Foo { + fn create() -> Foo; + fn doit(&self); + } + + pub fn bar() { + let foo = Foo::bar(); + } + } + "#) + .file("test.ts", r#" + import * as wasm from "./out"; + import * as assert from "assert"; + + let called = false; + + export class Foo { + static create() { + return new Foo(); + } + + doit() { + called = true; + } + } + + export function test() { + wasm.bar(); + assert.strictEqual(called, true); } "#) .test();