Enable returning a vector of js values

This commit is contained in:
Ryan Levick 2018-02-28 10:56:56 +01:00
parent 19f88f0fd2
commit dab6ba1df8
4 changed files with 79 additions and 1 deletions

View File

@ -656,6 +656,25 @@ impl<'a> Context<'a> {
}
}
fn expose_get_array_js_value_from_wasm(&mut self) {
if !self.exposed_globals.insert("get_array_js_value_from_wasm") {
return
}
self.expose_get_array_u8_from_wasm();
self.expose_get_object();
self.globals.push_str(&format!("
function getArrayJsValueFromWasm(ptr, len) {{
const mem = getUint8Memory();
const slice = mem.slice(ptr, ptr + len);
const result = []
for (ptr in slice) {{
result.push(getObject(ptr))
}}
return result;
}}
"));
}
fn expose_get_array_i8_from_wasm(&mut self) {
self.expose_uint8_memory();
if !self.exposed_globals.insert("get_array_i8_from_wasm") {
@ -925,6 +944,7 @@ impl<'a> Context<'a> {
self.expose_pass_array_f64_to_wasm();
"passArrayF64ToWasm"
}
VectorKind::JsValue => panic!("Cannot pass Vec<JsValue> to function")
}
}
@ -966,6 +986,10 @@ impl<'a> Context<'a> {
self.expose_get_array_f64_from_wasm();
"getArrayF64FromWasm"
}
VectorKind::JsValue => {
self.expose_get_array_js_value_from_wasm();
"getArrayJsValueFromWasm"
}
}
}
}
@ -1184,7 +1208,8 @@ impl<'a, 'b> SubContext<'a, 'b> {
Some(shared::TYPE_VECTOR_U32) |
Some(shared::TYPE_VECTOR_I32) |
Some(shared::TYPE_VECTOR_F32) |
Some(shared::TYPE_VECTOR_F64) => {
Some(shared::TYPE_VECTOR_F64) |
Some(shared::TYPE_VECTOR_JSVALUE) => {
let ty = VectorType::from(function.ret.unwrap());
dst_ts.push_str(": ");
dst_ts.push_str(ty.js_ty());
@ -1466,6 +1491,7 @@ enum VectorKind {
U32,
F32,
F64,
JsValue
}
impl VectorType {
@ -1525,6 +1551,9 @@ impl VectorType {
shared::TYPE_SLICE_F64 => {
VectorType { owned: false, kind: VectorKind::F64 }
}
shared::TYPE_VECTOR_JSVALUE => {
VectorType { owned: true, kind: VectorKind::JsValue }
}
_ => panic!()
}
}
@ -1540,6 +1569,7 @@ impl VectorType {
VectorKind::U32 => "Uint32Array",
VectorKind::F32 => "Float32Array",
VectorKind::F64 => "Float64Array",
VectorKind::JsValue => "object[]",
}
}
}

View File

@ -72,6 +72,7 @@ pub enum VectorType {
U32,
F32,
F64,
JsValue,
}
impl Program {
@ -544,6 +545,8 @@ impl Type {
Type::Vector(VectorType::F32, false) => a.char(shared::TYPE_SLICE_F32),
Type::Vector(VectorType::F64, true) => a.char(shared::TYPE_VECTOR_F64),
Type::Vector(VectorType::F64, false) => a.char(shared::TYPE_SLICE_F64),
Type::Vector(VectorType::JsValue, true) => a.char(shared::TYPE_VECTOR_JSVALUE),
Type::Vector(VectorType::JsValue, false) => panic!("Slices of JsValues not supported"),
Type::ByValue(ref t) => {
a.as_char(my_quote! {
<#t as ::wasm_bindgen::convert::WasmBoundary>::DESCRIPTOR
@ -978,6 +981,7 @@ impl VectorType {
"u32" => Some(VectorType::U32),
"f32" => Some(VectorType::F32),
"f64" => Some(VectorType::F64),
"JsValue" => Some(VectorType::JsValue),
_ => None,
}
}
@ -993,6 +997,7 @@ impl VectorType {
VectorType::U32 => syn::Ident::from("u32"),
VectorType::F32 => syn::Ident::from("f32"),
VectorType::F64 => syn::Ident::from("f64"),
VectorType::JsValue => syn::Ident::from("JsValue"),
}
}
}
@ -1009,6 +1014,7 @@ impl ToTokens for VectorType {
VectorType::U32 => my_quote! { Vec<u32> },
VectorType::F32 => my_quote! { Vec<f32> },
VectorType::F64 => my_quote! { Vec<f64> },
VectorType::JsValue => my_quote! { Vec<JsValue> },
};
me.to_tokens(tokens);
}

View File

@ -90,6 +90,8 @@ pub fn mangled_import_name(struct_: Option<&str>, f: &str) -> String {
pub type Type = char;
pub const TYPE_VECTOR_JSVALUE: char = '\u{5b}';
// Note: '\u{5c}' is '\' which breaks json encoding/decoding
pub const TYPE_ENUM: char = '\u{5d}';
pub const TYPE_NUMBER: char = '\u{5e}';
pub const TYPE_BORROWED_STR: char = '\u{5f}';

View File

@ -176,3 +176,43 @@ fn promote() {
"#)
.test();
}
#[test]
fn returning_vector() {
test_support::project()
.file("src/lib.rs", r#"
#![feature(proc_macro)]
extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;
#[wasm_bindgen(module = "./test")]
extern {
fn foo() -> JsValue;
}
#[wasm_bindgen]
#[no_mangle]
pub extern fn bar() -> Vec<JsValue> {
let mut res = Vec::new();
for _ in 0..10 {
res.push(foo())
}
res
}
"#)
.file("test.ts", r#"
import * as wasm from "./out";
import * as assert from "assert";
export function foo(): any { return { "foo": "bar" } }
export function test() {
const result = wasm.bar();
assert.strictEqual(result.length, 10);
}
"#)
.test();
}