From 73619b5d157a1e2141f22d828e68c9da13120a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Flemstr=C3=B6m?= Date: Wed, 28 Mar 2018 01:22:31 +0200 Subject: [PATCH 1/5] Add support for constructing JsValue instances generically --- crates/backend/src/codegen.rs | 16 ++++++++++++ crates/cli-support/src/js.rs | 10 ++++++++ crates/shared/src/lib.rs | 9 +++++++ src/lib.rs | 8 +++--- tests/classes.rs | 47 +++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 4 deletions(-) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 5c2ae3d7..8778f1cc 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -88,6 +88,7 @@ impl ToTokens for ast::Program { impl ToTokens for ast::Struct { fn to_tokens(&self, tokens: &mut Tokens) { let name = &self.name; + let new_fn = syn::Ident::from(shared::new_function(self.name.as_ref())); let free_fn = syn::Ident::from(shared::free_function(self.name.as_ref())); let c = shared::name_to_descriptor(name.as_ref()); let descriptor = Literal::byte_string(format!("{:4}", c).as_bytes()); @@ -153,6 +154,21 @@ impl ToTokens for ast::Struct { } } + impl ::std::convert::From<#name> for ::wasm_bindgen::JsValue { + fn from(value: #name) -> Self { + let ptr = ::wasm_bindgen::convert::WasmBoundary::into_js(value); + + #[wasm_import_module = "__wbindgen_placeholder__"] + extern { + fn #new_fn(ptr: u32) -> u32; + } + + unsafe { + ::wasm_bindgen::JsValue::__from_idx(#new_fn(ptr)) + } + } + } + #[no_mangle] pub unsafe extern fn #free_fn(ptr: u32) { <#name as ::wasm_bindgen::convert::WasmBoundary>::from_abi( diff --git a/crates/cli-support/src/js.rs b/crates/cli-support/src/js.rs index 3afbbd31..a22288f2 100644 --- a/crates/cli-support/src/js.rs +++ b/crates/cli-support/src/js.rs @@ -266,6 +266,11 @@ impl<'a> Context<'a> { }} ")); ts_dst.push_str("constructor(ptr: number, sym: Symbol);\n"); + + self.globals.push_str(&format!(" + export function {new_name}(ptr) {{ + return addHeapObject(new {class}(ptr, token)); + }}", new_name=shared::new_function(&class), class=class)); } else { dst.push_str(&format!(" constructor(ptr) {{ @@ -273,6 +278,11 @@ impl<'a> Context<'a> { }} ")); ts_dst.push_str("constructor(ptr: number);\n"); + + self.globals.push_str(&format!(" + export function {new_name}(ptr) {{ + return addHeapObject(new {class}(ptr)); + }}", new_name=shared::new_function(&class), class=class)); } dst.push_str(&format!(" diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 9d67f95c..30126d9f 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -88,6 +88,15 @@ pub struct CustomTypeName { pub name: String, } +pub fn new_function(struct_name: &str) -> String { + let mut name = format!("__wbg_"); + name.extend(struct_name + .chars() + .flat_map(|s| s.to_lowercase())); + name.push_str("_new"); + return name +} + pub fn free_function(struct_name: &str) -> String { let mut name = format!("__wbg_"); name.extend(struct_name diff --git a/src/lib.rs b/src/lib.rs index e9e3cb31..9b8bc817 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,10 +94,10 @@ impl JsValue { } } - // #[doc(hidden)] - // pub fn __from_idx(idx: u32) -> JsValue { - // JsValue { idx } - // } + #[doc(hidden)] + pub unsafe fn __from_idx(idx: u32) -> JsValue { + JsValue { idx } + } // // #[doc(hidden)] // pub fn __get_idx(&self) -> u32 { diff --git a/tests/classes.rs b/tests/classes.rs index 13e03b26..6d22be72 100644 --- a/tests/classes.rs +++ b/tests/classes.rs @@ -314,3 +314,50 @@ fn issue_27() { "#) .test(); } + +#[test] +fn pass_into_js_as_js_class() { + test_support::project() + .file("src/lib.rs", r#" + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] + + extern crate wasm_bindgen; + + use wasm_bindgen::prelude::*; + + #[wasm_bindgen] + pub struct Foo(i32); + + #[wasm_bindgen] + impl Foo { + pub fn inner(&self) -> i32 { + self.0 + } + } + + #[wasm_bindgen(module = "./test")] + extern { + fn take_foo(foo: JsValue); + } + + #[wasm_bindgen] + pub fn run() { + take_foo(Foo(13).into()); + } + "#) + .file("test.ts", r#" + import { run, Foo } from "./out"; + import * as assert from "assert"; + + export function take_foo(foo: any) { + assert(foo instanceof Foo); + assert.strictEqual(foo.inner(), 13); + foo.free(); + } + + export function test() { + run(); + } + "#) + .test(); +} From 188d3685832b1f0da464be81ba445e0ca34f3ce6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Apr 2018 09:58:15 -0700 Subject: [PATCH 2/5] Add some missing features to tests --- tests/classes.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/classes.rs b/tests/classes.rs index 6d22be72..5c47a840 100644 --- a/tests/classes.rs +++ b/tests/classes.rs @@ -4,7 +4,7 @@ extern crate test_support; fn simple() { test_support::project() .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; @@ -56,7 +56,7 @@ fn simple() { fn strings() { test_support::project() .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; @@ -114,7 +114,7 @@ fn strings() { fn exceptions() { test_support::project() .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; @@ -179,7 +179,7 @@ fn exceptions() { fn pass_one_to_another() { test_support::project() .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; @@ -276,7 +276,7 @@ fn pass_into_js() { fn issue_27() { test_support::project() .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; use wasm_bindgen::prelude::*; From 03433a0ef6a1bf4f245fa08adee3f2ef8d201780 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Apr 2018 09:58:27 -0700 Subject: [PATCH 3/5] Update to recent WasmBoundary abi changes --- crates/backend/src/codegen.rs | 11 +++++++++-- src/lib.rs | 8 ++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 8778f1cc..e7f57379 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -156,7 +156,10 @@ impl ToTokens for ast::Struct { impl ::std::convert::From<#name> for ::wasm_bindgen::JsValue { fn from(value: #name) -> Self { - let ptr = ::wasm_bindgen::convert::WasmBoundary::into_js(value); + let ptr = ::wasm_bindgen::convert::WasmBoundary::into_abi( + value, + unsafe { &mut ::wasm_bindgen::convert::GlobalStack::new() }, + ); #[wasm_import_module = "__wbindgen_placeholder__"] extern { @@ -164,7 +167,11 @@ impl ToTokens for ast::Struct { } unsafe { - ::wasm_bindgen::JsValue::__from_idx(#new_fn(ptr)) + <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::WasmBoundary> + ::from_abi( + #new_fn(ptr), + unsafe { &mut ::wasm_bindgen::convert::GlobalStack::new() }, + ) } } } diff --git a/src/lib.rs b/src/lib.rs index 9b8bc817..3b4c9bee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,10 +94,10 @@ impl JsValue { } } - #[doc(hidden)] - pub unsafe fn __from_idx(idx: u32) -> JsValue { - JsValue { idx } - } + // #[doc(hidden)] + // pub unsafe fn __from_idx(idx: u32) -> JsValue { + // JsValue { idx } + // } // // #[doc(hidden)] // pub fn __get_idx(&self) -> u32 { From 86625e78bcf2d8e7a2bf7a5b4b89b73467fff6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Flemstr=C3=B6m?= Date: Tue, 3 Apr 2018 11:00:41 +0200 Subject: [PATCH 4/5] Fix tests that are missing wasm_import_module --- tests/dependencies.rs | 4 ++-- tests/non-debug.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/dependencies.rs b/tests/dependencies.rs index 174ab985..9e7d4408 100644 --- a/tests/dependencies.rs +++ b/tests/dependencies.rs @@ -6,7 +6,7 @@ fn dependencies_work() { .file( "src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; extern crate dependency; use wasm_bindgen::prelude::*; @@ -51,7 +51,7 @@ fn dependencies_work() { .file( "vendor/dependency/src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; use wasm_bindgen::prelude::*; diff --git a/tests/non-debug.rs b/tests/non-debug.rs index cff3a6b4..71fd88fd 100644 --- a/tests/non-debug.rs +++ b/tests/non-debug.rs @@ -5,7 +5,7 @@ fn works() { test_support::project() .debug(false) .file("src/lib.rs", r#" - #![feature(proc_macro, wasm_custom_section)] + #![feature(proc_macro, wasm_custom_section, wasm_import_module)] extern crate wasm_bindgen; From 540ccfac9d85cf81a34627784aeda89f23e20ce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Flemstr=C3=B6m?= Date: Tue, 3 Apr 2018 11:10:15 +0200 Subject: [PATCH 5/5] Only generate JS class constructor export if import is needed --- crates/cli-support/src/js.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/crates/cli-support/src/js.rs b/crates/cli-support/src/js.rs index a22288f2..dd328689 100644 --- a/crates/cli-support/src/js.rs +++ b/crates/cli-support/src/js.rs @@ -267,10 +267,14 @@ impl<'a> Context<'a> { ")); ts_dst.push_str("constructor(ptr: number, sym: Symbol);\n"); - self.globals.push_str(&format!(" - export function {new_name}(ptr) {{ - return addHeapObject(new {class}(ptr, token)); - }}", new_name=shared::new_function(&class), class=class)); + let new_name = shared::new_function(&class); + if self.wasm_import_needed(&new_name) { + self.globals.push_str(&format!(" + export function {new_name}(ptr) {{ + return addHeapObject(new {class}(ptr, token)); + }} + ", new_name = new_name, class = class)); + } } else { dst.push_str(&format!(" constructor(ptr) {{ @@ -279,10 +283,14 @@ impl<'a> Context<'a> { ")); ts_dst.push_str("constructor(ptr: number);\n"); - self.globals.push_str(&format!(" - export function {new_name}(ptr) {{ - return addHeapObject(new {class}(ptr)); - }}", new_name=shared::new_function(&class), class=class)); + let new_name = shared::new_function(&class); + if self.wasm_import_needed(&new_name) { + self.globals.push_str(&format!(" + export function {new_name}(ptr) {{ + return addHeapObject(new {class}(ptr)); + }} + ", new_name = new_name, class = class)); + } } dst.push_str(&format!("