Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement To/FromWasmAbi traits for boxed slices of JsValue wrappers #2614

Merged
merged 7 commits into from
Jul 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ impl ToTokens for ast::ImportType {
use wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
use wasm_bindgen::convert::RefFromWasmAbi;
use wasm_bindgen::describe::WasmDescribe;
use wasm_bindgen::{JsValue, JsCast};
use wasm_bindgen::{JsValue, JsCast, JsObject};
use wasm_bindgen::__rt::core;

impl WasmDescribe for #rust_name {
Expand Down Expand Up @@ -761,6 +761,8 @@ impl ToTokens for ast::ImportType {
}
}

impl JsObject for #rust_name {}

()
};
})
Expand Down
36 changes: 21 additions & 15 deletions crates/cli-support/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub struct Closure {
pub mutable: bool,
}

#[derive(Copy, Clone, Debug)]
#[derive(Clone, Debug)]
pub enum VectorKind {
I8,
U8,
Expand All @@ -101,6 +101,7 @@ pub enum VectorKind {
F64,
String,
Externref,
NamedExternref(String),
}

impl Descriptor {
Expand Down Expand Up @@ -193,6 +194,7 @@ impl Descriptor {
Descriptor::F32 => Some(VectorKind::F32),
Descriptor::F64 => Some(VectorKind::F64),
Descriptor::Externref => Some(VectorKind::Externref),
Descriptor::NamedExternref(ref name) => Some(VectorKind::NamedExternref(name.clone())),
_ => None,
}
}
Expand Down Expand Up @@ -240,21 +242,24 @@ impl Function {
}

impl VectorKind {
pub fn js_ty(&self) -> &str {
pub fn js_ty(&self) -> String {
match *self {
VectorKind::String => "string",
VectorKind::I8 => "Int8Array",
VectorKind::U8 => "Uint8Array",
VectorKind::ClampedU8 => "Uint8ClampedArray",
VectorKind::I16 => "Int16Array",
VectorKind::U16 => "Uint16Array",
VectorKind::I32 => "Int32Array",
VectorKind::U32 => "Uint32Array",
VectorKind::I64 => "BigInt64Array",
VectorKind::U64 => "BigUint64Array",
VectorKind::F32 => "Float32Array",
VectorKind::F64 => "Float64Array",
VectorKind::Externref => "any[]",
VectorKind::String => "string".to_string(),
VectorKind::I8 => "Int8Array".to_string(),
VectorKind::U8 => "Uint8Array".to_string(),
VectorKind::ClampedU8 => "Uint8ClampedArray".to_string(),
VectorKind::I16 => "Int16Array".to_string(),
VectorKind::U16 => "Uint16Array".to_string(),
VectorKind::I32 => "Int32Array".to_string(),
VectorKind::U32 => "Uint32Array".to_string(),
VectorKind::I64 => "BigInt64Array".to_string(),
VectorKind::U64 => "BigUint64Array".to_string(),
VectorKind::F32 => "Float32Array".to_string(),
VectorKind::F64 => "Float64Array".to_string(),
VectorKind::Externref => "any[]".to_string(),
VectorKind::NamedExternref(ref name) => {
format!("({})[]", name)
}
}
}

Expand All @@ -273,6 +278,7 @@ impl VectorKind {
VectorKind::F32 => 4,
VectorKind::F64 => 8,
VectorKind::Externref => 4,
VectorKind::NamedExternref(_) => 4,
}
}
}
14 changes: 7 additions & 7 deletions crates/cli-support/src/externref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,31 +351,31 @@ fn module_needs_externref_metadata(aux: &WasmBindgenAux, section: &NonstandardWi
};
instructions.iter().any(|instr| match instr.instr {
VectorToMemory {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
}
| MutableSliceToMemory {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
}
| OptionVector {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
}
| VectorLoad {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
}
| OptionVectorLoad {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
}
| View {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
}
| OptionView {
kind: VectorKind::Externref,
kind: VectorKind::Externref | VectorKind::NamedExternref(_),
..
} => true,
_ => false,
Expand Down
18 changes: 9 additions & 9 deletions crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->

Instruction::VectorToMemory { kind, malloc, mem } => {
let val = js.pop();
let func = js.cx.pass_to_wasm_function(*kind, *mem)?;
let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?;
let malloc = js.cx.export_name_of(*malloc);
let i = js.tmp();
js.prelude(&format!(
Expand Down Expand Up @@ -805,7 +805,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
}

Instruction::OptionVector { kind, mem, malloc } => {
let func = js.cx.pass_to_wasm_function(*kind, *mem)?;
let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?;
js.cx.expose_is_like_none();
let i = js.tmp();
let malloc = js.cx.export_name_of(*malloc);
Expand All @@ -832,7 +832,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
// a length. These two pointer/length values get pushed onto the
// value stack.
let val = js.pop();
let func = js.cx.pass_to_wasm_function(*kind, *mem)?;
let func = js.cx.pass_to_wasm_function(kind.clone(), *mem)?;
let malloc = js.cx.export_name_of(*malloc);
let i = js.tmp();
js.prelude(&format!(
Expand All @@ -850,7 +850,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
// original mutable slice with any modifications, and then free the
// Rust-backed memory.
let free = js.cx.export_name_of(*free);
let get = js.cx.memview_function(*kind, *mem);
let get = js.cx.memview_function(kind.clone(), *mem);
js.finally(&format!(
"
{val}.set({get}().subarray(ptr{i} / {size}, ptr{i} / {size} + len{i}));
Expand Down Expand Up @@ -1003,7 +1003,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
Instruction::VectorLoad { kind, mem, free } => {
let len = js.pop();
let ptr = js.pop();
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
let f = js.cx.expose_get_vector_from_wasm(kind.clone(), *mem)?;
let i = js.tmp();
let free = js.cx.export_name_of(*free);
js.prelude(&format!("var v{} = {}({}, {}).slice();", i, f, ptr, len));
Expand All @@ -1020,7 +1020,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
Instruction::OptionVectorLoad { kind, mem, free } => {
let len = js.pop();
let ptr = js.pop();
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
let f = js.cx.expose_get_vector_from_wasm(kind.clone(), *mem)?;
let i = js.tmp();
let free = js.cx.export_name_of(*free);
js.prelude(&format!("let v{};", i));
Expand All @@ -1040,14 +1040,14 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
Instruction::View { kind, mem } => {
let len = js.pop();
let ptr = js.pop();
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
let f = js.cx.expose_get_vector_from_wasm(kind.clone(), *mem)?;
js.push(format!("{f}({ptr}, {len})", ptr = ptr, len = len, f = f));
}

Instruction::OptionView { kind, mem } => {
let len = js.pop();
let ptr = js.pop();
let f = js.cx.expose_get_vector_from_wasm(*kind, *mem)?;
let f = js.cx.expose_get_vector_from_wasm(kind.clone(), *mem)?;
js.push(format!(
"{ptr} === 0 ? undefined : {f}({ptr}, {len})",
ptr = ptr,
Expand Down Expand Up @@ -1226,7 +1226,7 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String) {
AdapterType::String => dst.push_str("string"),
AdapterType::Externref => dst.push_str("any"),
AdapterType::Bool => dst.push_str("boolean"),
AdapterType::Vector(kind) => dst.push_str(kind.js_ty()),
AdapterType::Vector(kind) => dst.push_str(&kind.js_ty()),
AdapterType::Option(ty) => {
adapter2ts(ty, dst);
dst.push_str(" | undefined");
Expand Down
3 changes: 3 additions & 0 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,7 @@ impl<'a> Context<'a> {
VectorKind::F32 => self.expose_f32_memory(memory),
VectorKind::F64 => self.expose_f64_memory(memory),
VectorKind::Externref => self.expose_uint32_memory(memory),
VectorKind::NamedExternref(_) => self.expose_uint32_memory(memory),
}
}

Expand Down Expand Up @@ -1842,6 +1843,7 @@ impl<'a> Context<'a> {
VectorKind::F32 => self.expose_pass_array_f32_to_wasm(memory),
VectorKind::F64 => self.expose_pass_array_f64_to_wasm(memory),
VectorKind::Externref => self.expose_pass_array_jsvalue_to_wasm(memory),
VectorKind::NamedExternref(_) => self.expose_pass_array_jsvalue_to_wasm(memory),
}
}

Expand All @@ -1864,6 +1866,7 @@ impl<'a> Context<'a> {
VectorKind::F32 => self.expose_get_array_f32_from_wasm(memory),
VectorKind::F64 => self.expose_get_array_f64_from_wasm(memory),
VectorKind::Externref => self.expose_get_array_js_value_from_wasm(memory)?,
VectorKind::NamedExternref(_) => self.expose_get_array_js_value_from_wasm(memory)?,
})
}

Expand Down
8 changes: 4 additions & 4 deletions crates/cli-support/src/wit/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ impl InstructionBuilder<'_, '_> {
format_err!("unsupported argument type for calling Rust function from JS {:?}", arg)
})?;
self.instruction(
&[AdapterType::Vector(kind)],
&[AdapterType::Vector(kind.clone())],
Instruction::VectorToMemory {
kind,
malloc: self.cx.malloc()?,
Expand Down Expand Up @@ -198,7 +198,7 @@ impl InstructionBuilder<'_, '_> {
})?;
if mutable {
self.instruction(
&[AdapterType::Vector(kind)],
&[AdapterType::Vector(kind.clone())],
Instruction::MutableSliceToMemory {
kind,
malloc: self.cx.malloc()?,
Expand All @@ -209,7 +209,7 @@ impl InstructionBuilder<'_, '_> {
);
} else {
self.instruction(
&[AdapterType::Vector(kind)],
&[AdapterType::Vector(kind.clone())],
Instruction::VectorToMemory {
kind,
malloc: self.cx.malloc()?,
Expand Down Expand Up @@ -322,7 +322,7 @@ impl InstructionBuilder<'_, '_> {
let malloc = self.cx.malloc()?;
let mem = self.cx.memory()?;
self.instruction(
&[AdapterType::Vector(kind).option()],
&[AdapterType::Vector(kind.clone()).option()],
Instruction::OptionVector { kind, malloc, mem },
&[AdapterType::I32, AdapterType::I32],
);
Expand Down
22 changes: 18 additions & 4 deletions crates/cli-support/src/wit/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,11 @@ impl InstructionBuilder<'_, '_> {
let free = self.cx.free()?;
self.instruction(
&[AdapterType::I32, AdapterType::I32],
Instruction::VectorLoad { kind, mem, free },
Instruction::VectorLoad {
kind: kind.clone(),
mem,
free,
},
&[AdapterType::Vector(kind)],
);
}
Expand Down Expand Up @@ -196,7 +200,10 @@ impl InstructionBuilder<'_, '_> {
let mem = self.cx.memory()?;
self.instruction(
&[AdapterType::I32, AdapterType::I32],
Instruction::View { kind, mem },
Instruction::View {
kind: kind.clone(),
mem,
},
&[AdapterType::Vector(kind)],
);
}
Expand Down Expand Up @@ -313,7 +320,11 @@ impl InstructionBuilder<'_, '_> {
let free = self.cx.free()?;
self.instruction(
&[AdapterType::I32, AdapterType::I32],
Instruction::OptionVectorLoad { kind, mem, free },
Instruction::OptionVectorLoad {
kind: kind.clone(),
mem,
free,
},
&[AdapterType::Vector(kind).option()],
);
}
Expand Down Expand Up @@ -355,7 +366,10 @@ impl InstructionBuilder<'_, '_> {
let mem = self.cx.memory()?;
self.instruction(
&[AdapterType::I32, AdapterType::I32],
Instruction::OptionView { kind, mem },
Instruction::OptionView {
kind: kind.clone(),
mem,
},
&[AdapterType::Vector(kind).option()],
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/cast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::JsValue;
use crate::{describe::WasmDescribe, JsValue};

/// A trait for checked and unchecked casting between JS types.
///
Expand Down Expand Up @@ -154,3 +154,7 @@ where
/// won't need to call this.
fn unchecked_from_js_ref(val: &JsValue) -> &Self;
}

/// Trait implemented for wrappers around `JsValue`s generated by `#[wasm_bindgen]`.
#[doc(hidden)]
pub trait JsObject: JsCast + WasmDescribe {}
38 changes: 38 additions & 0 deletions src/convert/slices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::prelude::v1::*;
use core::slice;
use core::str;

use crate::cast::JsObject;
use crate::convert::OptionIntoWasmAbi;
use crate::convert::{FromWasmAbi, IntoWasmAbi, RefFromWasmAbi, RefMutFromWasmAbi, WasmAbi};
use cfg_if::cfg_if;
Expand Down Expand Up @@ -270,4 +271,41 @@ if_std! {
#[inline]
fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 }
}

impl<T> IntoWasmAbi for Box<[T]> where T: JsObject {
type Abi = WasmSlice;

#[inline]
fn into_abi(self) -> WasmSlice {
let ptr = self.as_ptr();
let len = self.len();
mem::forget(self);
WasmSlice {
ptr: ptr.into_abi(),
len: len as u32,
}
}
}

impl<T> OptionIntoWasmAbi for Box<[T]> where T: JsObject {
#[inline]
fn none() -> WasmSlice { null_slice() }
}

impl<T> FromWasmAbi for Box<[T]> where T: JsObject {
type Abi = WasmSlice;

#[inline]
unsafe fn from_abi(js: WasmSlice) -> Self {
let ptr = <*mut JsValue>::from_abi(js.ptr);
let len = js.len as usize;
let vec: Vec<T> = Vec::from_raw_parts(ptr, len, len).drain(..).map(|js_value| T::unchecked_from_js(js_value)).collect();
return vec.into_boxed_slice();
}
}

impl<T> OptionFromWasmAbi for Box<[T]> where T: JsObject {
#[inline]
fn is_none(slice: &WasmSlice) -> bool { slice.ptr == 0 }
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub mod convert;
pub mod describe;

mod cast;
pub use crate::cast::JsCast;
pub use crate::cast::{JsCast, JsObject};

if_std! {
extern crate std;
Expand Down
Loading