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

[WIP] Adds support to enums with values #2631

Closed
Closed
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
2 changes: 2 additions & 0 deletions crates/backend/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ pub struct Enum {
pub struct Variant {
/// The name of this variant
pub name: Ident,
/// The fields of this variant
pub fields: syn::Fields,
/// The backing value of this variant
pub value: u32,
/// The doc comments on this variant, if any
Expand Down
75 changes: 63 additions & 12 deletions crates/backend/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1161,57 +1161,108 @@ impl<'a> ToTokens for DescribeImport<'a> {

impl ToTokens for ast::Enum {
fn to_tokens(&self, into: &mut TokenStream) {
use quote::format_ident;

let enum_name = &self.rust_name;
let hole = &self.hole;
let cast_clauses = self.variants.iter().map(|variant| {
let variant_name = &variant.name;
let variant_value = &variant.value;

let fields = &variant.fields.clone();
let variant_fields_into_array = fields.iter().map(|field| {
quote! {
#field::from_abi(<#field as FromWasmAbi>::Abi::pop_from_u32_vector(&mut vector))
}
});

quote! {
if js == #enum_name::#variant_name as u32 {
#enum_name::#variant_name
if vector.pop().unwrap() == #variant_value {
#enum_name::#variant_name(#(#variant_fields_into_array),*)
}
}
});
let into_clauses = self.variants.iter().map(|variant| {
let variant_name = &variant.name;
let variant_value = &variant.value;

let fields = &variant.fields.clone();
let field_vector_into_tuple = fields.iter().enumerate().map(|(index, _)| {
let varname = format_ident!("arg{}", index);
quote! {
#varname
}
});

let field_names = field_vector_into_tuple.clone();

quote! {
#enum_name::#variant_name(#(#field_vector_into_tuple),*)
=> {
let mut vector = vec![(#variant_value).into_abi()];
#((#field_names).into_abi().push_into_u32_vector(&mut vector));*;
vector
}
}
});
(quote! {
use wasm_bindgen::convert::{WasmAbi, WasmSlice, FromWasmAbi, VectorEncoding};

#[allow(clippy::all)]
impl wasm_bindgen::convert::IntoWasmAbi for #enum_name {
type Abi = u32;
type Abi = WasmSlice;

#[inline]
fn into_abi(self) -> u32 {
self as u32
fn into_abi(self) -> WasmSlice {
let vector = match self {
#(#into_clauses),*
};

let ptr = vector.as_ptr();
let len = vector.len();
core::mem::forget(vector);
WasmSlice {
ptr: ptr.into_abi(),
len: len as u32,
}
}
}

#[allow(clippy::all)]
impl wasm_bindgen::convert::FromWasmAbi for #enum_name {
type Abi = u32;
type Abi = WasmSlice;

#[inline]
unsafe fn from_abi(js: u32) -> Self {
unsafe fn from_abi(js: WasmSlice) -> Self {
let ptr = <*mut u32>::from_abi(js.ptr);
let len = js.len as usize;
let mut vector = Vec::from_raw_parts(ptr, len, len);
let err = format!("{:?}", vector.len()).as_str();

#(#cast_clauses else)* {
wasm_bindgen::throw_str("invalid enum value passed")
wasm_bindgen::throw_str(err,)
}
}
}

#[allow(clippy::all)]
impl wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
#[inline]
fn is_none(val: &u32) -> bool { *val == #hole }
fn is_none(val: &WasmSlice) -> bool {
val.ptr == (#hole as u32)
}
}

#[allow(clippy::all)]
impl wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
#[inline]
fn none() -> Self::Abi { #hole }
fn none() -> Self::Abi { WasmSlice { ptr: 0, len: 0 } }
}

#[allow(clippy::all)]
impl wasm_bindgen::describe::WasmDescribe for #enum_name {
fn describe() {
use wasm_bindgen::describe::*;
inform(ENUM);
inform(#hole);
}
}
})
Expand Down
30 changes: 28 additions & 2 deletions crates/cli-support/src/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub enum Descriptor {
String,
Externref,
NamedExternref(String),
Enum { hole: u32 },
Enum,
RustStruct(String),
Char,
Option(Box<Descriptor>),
Expand Down Expand Up @@ -104,6 +104,12 @@ pub enum VectorKind {
NamedExternref(String),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct EnumVariant {
pub name: String,
pub fields: Vec<Descriptor>
}

impl Descriptor {
pub fn decode(mut data: &[u32]) -> Descriptor {
let descriptor = Descriptor::_decode(&mut data, false);
Expand Down Expand Up @@ -135,7 +141,7 @@ impl Descriptor {
CACHED_STRING => Descriptor::CachedString,
STRING => Descriptor::String,
EXTERNREF => Descriptor::Externref,
ENUM => Descriptor::Enum { hole: get(data) },
ENUM => Descriptor::Enum,
RUST_STRUCT => {
let name = get_string(data);
Descriptor::RustStruct(name)
Expand Down Expand Up @@ -212,6 +218,26 @@ fn get_string(data: &mut &[u32]) -> String {
.collect()
}

// fn get_enum(data: &mut &[u32]) -> Descriptor {
// let name = get_string(data);
// let hole = get(data);
// let variants = (0..get(data)).map(|_| {

// let variant_name = get_string(data);
// let variant_fields = (0..get(data)).map(|_| {
// Descriptor::_decode(data, false)
// }).collect();

// EnumVariant {
// name: variant_name,
// fields: variant_fields
// }

// }).collect();

// Descriptor::Enum {name, variants, hole}
// }

impl Closure {
fn decode(data: &mut &[u32]) -> Closure {
let shim_idx = get(data);
Expand Down
1 change: 1 addition & 0 deletions crates/cli-support/src/js/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1234,5 +1234,6 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String) {
AdapterType::NamedExternref(name) => dst.push_str(name),
AdapterType::Struct(name) => dst.push_str(name),
AdapterType::Function => dst.push_str("any"),
AdapterType::Enum => dst.push_str("placeholder")
}
}
24 changes: 19 additions & 5 deletions crates/cli-support/src/wit/incoming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,17 @@ impl InstructionBuilder<'_, '_> {
self.get(AdapterType::F64);
self.output.push(AdapterType::F64);
}
Descriptor::Enum { .. } => self.number(WitVT::U32, WasmVT::I32),
Descriptor::Enum { .. } => {
let kind = crate::descriptor::VectorKind::U32;

let malloc = self.cx.malloc()?;
let mem = self.cx.memory()?;
self.instruction(
&[AdapterType::Enum.option()],
Instruction::OptionVector { kind, malloc, mem },
&[AdapterType::I32, AdapterType::I32],
);
}
Descriptor::Ref(d) => self.incoming_ref(false, d)?,
Descriptor::RefMut(d) => self.incoming_ref(true, d)?,
Descriptor::Option(d) => self.incoming_option(d)?,
Expand Down Expand Up @@ -280,11 +290,15 @@ impl InstructionBuilder<'_, '_> {
&[AdapterType::I32],
);
}
Descriptor::Enum { hole } => {
Descriptor::Enum { .. } => {
let kind = crate::descriptor::VectorKind::U32;

let malloc = self.cx.malloc()?;
let mem = self.cx.memory()?;
self.instruction(
&[AdapterType::U32.option()],
Instruction::I32FromOptionEnum { hole: *hole },
&[AdapterType::I32],
&[AdapterType::Enum.option()],
Instruction::OptionVector { kind, malloc, mem },
&[AdapterType::I32, AdapterType::I32],
);
}
Descriptor::RustStruct(name) => {
Expand Down
31 changes: 23 additions & 8 deletions crates/cli-support/src/wit/outgoing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ impl InstructionBuilder<'_, '_> {
self.get(AdapterType::F64);
self.output.push(AdapterType::F64);
}
Descriptor::Enum { .. } => self.outgoing_i32(AdapterType::U32),

Descriptor::Char => {
self.instruction(
Expand Down Expand Up @@ -155,6 +154,22 @@ impl InstructionBuilder<'_, '_> {
arg
),

Descriptor::Enum { .. } => {
let kind = crate::descriptor::VectorKind::U32;

let mem = self.cx.memory()?;
let free = self.cx.free()?;
self.instruction(
&[AdapterType::I32, AdapterType::I32],
Instruction::VectorLoad {
kind,
mem,
free,
},
&[AdapterType::Enum],
);
}

// nothing to do
Descriptor::Unit => {}

Expand Down Expand Up @@ -288,13 +303,13 @@ impl InstructionBuilder<'_, '_> {
&[AdapterType::String.option()],
);
}
Descriptor::Enum { hole } => {
self.instruction(
&[AdapterType::I32],
Instruction::OptionEnumFromI32 { hole: *hole },
&[AdapterType::U32.option()],
);
}
// Descriptor::Enum => {
// self.instruction(
// &[AdapterType::I32],
// Instruction::OptionEnumFromI32 { hole: *hole },
// &[AdapterType::U32.option()],
// );
// }
Descriptor::RustStruct(name) => {
self.instruction(
&[AdapterType::I32],
Expand Down
10 changes: 9 additions & 1 deletion crates/cli-support/src/wit/standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ pub enum AdapterType {
Struct(String),
NamedExternref(String),
Function,
Enum,
}

#[derive(Debug, Clone)]
pub struct EnumVariantAdapter {
pub name: String,
pub fields: Vec<AdapterType>
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -354,7 +361,8 @@ impl AdapterType {
| AdapterType::Function
| AdapterType::Struct(_)
| AdapterType::Bool
| AdapterType::Vector(_) => return None,
| AdapterType::Vector(_)
| AdapterType::Enum => return None,
})
}

Expand Down
6 changes: 1 addition & 5 deletions crates/macro-support/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1159,11 +1159,6 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum {
.iter()
.enumerate()
.map(|(i, v)| {
match v.fields {
syn::Fields::Unit => (),
_ => bail_span!(v.fields, "only C-Style enums allowed with #[wasm_bindgen]"),
}

// Require that everything either has a discriminant or doesn't.
// We don't really want to get in the business of emulating how
// rustc assigns values to enums.
Expand Down Expand Up @@ -1203,6 +1198,7 @@ impl<'a> MacroParse<(&'a mut TokenStream, BindgenAttrs)> for syn::ItemEnum {
name: v.ident.clone(),
value,
comments,
fields: v.fields.clone(),
})
})
.collect::<Result<Vec<_>, Diagnostic>>()?;
Expand Down
2 changes: 1 addition & 1 deletion src/convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ mod slices;
mod traits;

pub use self::impls::*;
pub use self::slices::WasmSlice;
pub use self::slices::{WasmSlice, VectorEncoding};
pub use self::traits::*;
Loading