Fix String type in imports

This commit is contained in:
Alex Crichton 2018-02-06 08:39:49 -08:00
parent d2f2ed8c1a
commit 28966d9853
3 changed files with 78 additions and 11 deletions

View File

@ -536,6 +536,8 @@ impl<'a> Js<'a> {
self.expose_get_object(); self.expose_get_object();
} }
let mut extra = String::new();
for (i, arg) in import.arguments.iter().enumerate() { for (i, arg) in import.arguments.iter().enumerate() {
if invocation.len() > 0 { if invocation.len() > 0 {
invocation.push_str(", "); invocation.push_str(", ");
@ -557,6 +559,15 @@ impl<'a> Js<'a> {
invocation.push_str(&format!("getStringFromWasm(ptr{0}, len{0})", i)); invocation.push_str(&format!("getStringFromWasm(ptr{0}, len{0})", i));
dst.push_str(&format!("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 => { shared::TYPE_JS_OWNED => {
self.expose_take_object(); self.expose_take_object();
invocation.push_str(&format!("takeObject(arg{})", i)); 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 = format!("{}({})", shim_delegate, invocation);
let invoc = match import.ret { let invoc = match import.ret {
Some(shared::TYPE_NUMBER) => invoc, Some(shared::TYPE_NUMBER) => format!("return {};", invoc),
Some(shared::TYPE_BOOLEAN) => format!("{} ? 1 : 0", invoc), Some(shared::TYPE_BOOLEAN) => format!("return {} ? 1 : 0;", invoc),
Some(shared::TYPE_JS_OWNED) => { Some(shared::TYPE_JS_OWNED) => {
self.expose_add_heap_object(); 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, None => invoc,
_ => unimplemented!(), _ => unimplemented!(),
}; };
dst.push_str(" {\n"); dst.push_str(") {\n");
dst.push_str(&format!("return {};\n}}", invoc)); dst.push_str(&extra);
dst.push_str(&format!("{}\n}}", invoc));
self.globals.push_str("export "); self.globals.push_str("export ");
self.globals.push_str(&dst); self.globals.push_str(&dst);

View File

@ -583,15 +583,18 @@ fn bindgen_import_function(import: &ast::ImportFunction,
// TODO: add a test for this // TODO: add a test for this
Some(ast::Type::String) => { Some(ast::Type::String) => {
let name = syn::Ident::from("__ret_strlen"); let name = syn::Ident::from("__ret_strlen");
abi_argument_names.push(name); let name_ptr = syn::Ident::from("__ret_strlen_ptr");
abi_arguments.push(my_quote! { #name: *mut usize }); abi_argument_names.push(name_ptr);
abi_arguments.push(my_quote! { #name_ptr: *mut usize });
arg_conversions.push(my_quote! { arg_conversions.push(my_quote! {
let mut #name = 0; 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! { convert_ret = my_quote! {
let __v = Vec::from_raw_parts(#ret_ident, #name, #name); String::from_utf8_unchecked(
String::from_utf8_unchecked(__v) Vec::from_raw_parts(#ret_ident, #name, #name)
)
}; };
} }
Some(ast::Type::BorrowedStr) | Some(ast::Type::BorrowedStr) |

View File

@ -107,3 +107,44 @@ fn unused() {
"#) "#)
.test(); .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();
}