From 28966d98535cd954d3645c1537eb9c4ea9dd3aea Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 6 Feb 2018 08:39:49 -0800 Subject: [PATCH] Fix `String` type in imports --- crates/wasm-bindgen-cli-support/src/js.rs | 35 +++++++++++++++---- crates/wasm-bindgen-macro/src/lib.rs | 13 ++++--- tests/imports.rs | 41 +++++++++++++++++++++++ 3 files changed, 78 insertions(+), 11 deletions(-) diff --git a/crates/wasm-bindgen-cli-support/src/js.rs b/crates/wasm-bindgen-cli-support/src/js.rs index 4fb9b061..f48cbd01 100644 --- a/crates/wasm-bindgen-cli-support/src/js.rs +++ b/crates/wasm-bindgen-cli-support/src/js.rs @@ -536,6 +536,8 @@ impl<'a> Js<'a> { self.expose_get_object(); } + let mut extra = String::new(); + for (i, arg) in import.arguments.iter().enumerate() { if invocation.len() > 0 { invocation.push_str(", "); @@ -557,6 +559,15 @@ impl<'a> Js<'a> { invocation.push_str(&format!("getStringFromWasm(ptr{0}, len{0})", i)); dst.push_str(&format!("ptr{0}, len{0}", i)); } + shared::TYPE_STRING => { + self.expose_get_string_from_wasm(); + dst.push_str(&format!("ptr{0}, len{0}", i)); + extra.push_str(&format!(" + let arg{0} = getStringFromWasm(ptr{0}, len{0}); + wasm.__wbindgen_free(ptr{0}, len{0}); + ", i)); + invocation.push_str(&format!("arg{}", i)); + } shared::TYPE_JS_OWNED => { self.expose_take_object(); invocation.push_str(&format!("takeObject(arg{})", i)); @@ -572,20 +583,32 @@ impl<'a> Js<'a> { } } } - dst.push_str(")"); let invoc = format!("{}({})", shim_delegate, invocation); let invoc = match import.ret { - Some(shared::TYPE_NUMBER) => invoc, - Some(shared::TYPE_BOOLEAN) => format!("{} ? 1 : 0", invoc), + Some(shared::TYPE_NUMBER) => format!("return {};", invoc), + Some(shared::TYPE_BOOLEAN) => format!("return {} ? 1 : 0;", invoc), Some(shared::TYPE_JS_OWNED) => { self.expose_add_heap_object(); - format!("addHeapObject({})", invoc) + format!("return addHeapObject({});", invoc) + } + Some(shared::TYPE_STRING) => { + self.expose_pass_string_to_wasm(); + if import.arguments.len() > 0 || is_method { + dst.push_str(", "); + } + dst.push_str("wasmretptr"); + format!(" + const [retptr, retlen] = passStringToWasm({}); + (new Uint32Array(wasm.memory.buffer))[wasmretptr / 4] = retlen; + return retptr; + ", invoc) } None => invoc, _ => unimplemented!(), }; - dst.push_str(" {\n"); - dst.push_str(&format!("return {};\n}}", invoc)); + dst.push_str(") {\n"); + dst.push_str(&extra); + dst.push_str(&format!("{}\n}}", invoc)); self.globals.push_str("export "); self.globals.push_str(&dst); diff --git a/crates/wasm-bindgen-macro/src/lib.rs b/crates/wasm-bindgen-macro/src/lib.rs index 7372bc5f..aa13a41b 100644 --- a/crates/wasm-bindgen-macro/src/lib.rs +++ b/crates/wasm-bindgen-macro/src/lib.rs @@ -583,15 +583,18 @@ fn bindgen_import_function(import: &ast::ImportFunction, // TODO: add a test for this Some(ast::Type::String) => { let name = syn::Ident::from("__ret_strlen"); - abi_argument_names.push(name); - abi_arguments.push(my_quote! { #name: *mut usize }); + let name_ptr = syn::Ident::from("__ret_strlen_ptr"); + abi_argument_names.push(name_ptr); + abi_arguments.push(my_quote! { #name_ptr: *mut usize }); arg_conversions.push(my_quote! { let mut #name = 0; + let mut #name_ptr = &mut #name as *mut usize; }); - abi_ret = my_quote! { *const u8 }; + abi_ret = my_quote! { *mut u8 }; convert_ret = my_quote! { - let __v = Vec::from_raw_parts(#ret_ident, #name, #name); - String::from_utf8_unchecked(__v) + String::from_utf8_unchecked( + Vec::from_raw_parts(#ret_ident, #name, #name) + ) }; } Some(ast::Type::BorrowedStr) | diff --git a/tests/imports.rs b/tests/imports.rs index 545af4af..2ef9215d 100644 --- a/tests/imports.rs +++ b/tests/imports.rs @@ -107,3 +107,44 @@ fn unused() { "#) .test(); } + +#[test] +fn strings() { + 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 "JS" { + fn foo(a: String) -> String; + } + + pub fn bar(a: &str) -> String { + foo(a.to_string()) + } + + pub fn bar2(a: String) -> String { + foo(a) + } + } + "#) + .file("test.ts", r#" + import * as wasm from "./out"; + import * as assert from "assert"; + + export function foo(a: string): string { + return a + 'b'; + } + + export function test() { + assert.strictEqual(wasm.bar('a'), 'ab'); + assert.strictEqual(wasm.bar2('a'), 'ab'); + } + "#) + .test(); +}