Add support for constructing JsValue instances generically

This commit is contained in:
David Flemström 2018-03-28 01:22:31 +02:00 committed by Alex Crichton
parent e6a483f906
commit 73619b5d15
5 changed files with 86 additions and 4 deletions

View File

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

View File

@ -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!("

View File

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

View File

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

View File

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