diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 039449dc..964bd804 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,28 @@ 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_abi( + value, + unsafe { &mut ::wasm_bindgen::convert::GlobalStack::new() }, + ); + + #[wasm_import_module = "__wbindgen_placeholder__"] + extern { + fn #new_fn(ptr: u32) -> u32; + } + + unsafe { + <::wasm_bindgen::JsValue as ::wasm_bindgen::convert::WasmBoundary> + ::from_abi( + #new_fn(ptr), + unsafe { &mut ::wasm_bindgen::convert::GlobalStack::new() }, + ) + } + } + } + #[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..dd328689 100644 --- a/crates/cli-support/src/js.rs +++ b/crates/cli-support/src/js.rs @@ -266,6 +266,15 @@ impl<'a> Context<'a> { }} ")); ts_dst.push_str("constructor(ptr: number, sym: Symbol);\n"); + + 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) {{ @@ -273,6 +282,15 @@ impl<'a> Context<'a> { }} ")); ts_dst.push_str("constructor(ptr: number);\n"); + + 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!(" 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..3b4c9bee 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,7 +95,7 @@ impl JsValue { } // #[doc(hidden)] - // pub fn __from_idx(idx: u32) -> JsValue { + // pub unsafe fn __from_idx(idx: u32) -> JsValue { // JsValue { idx } // } // diff --git a/tests/classes.rs b/tests/classes.rs index 13e03b26..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::*; @@ -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(); +} 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;