use proc_macro2::TokenStream;
use quote::quote;
use crate::ir::{NumericEnumDecl, StringEnumDecl};
pub fn generate_string_enum(decl: &StringEnumDecl) -> TokenStream {
let name = super::typemap::make_ident(&decl.name);
let variants: Vec<_> = decl
.variants
.iter()
.map(|v| {
let rust_name = super::typemap::make_ident(&v.rust_name);
let js_value = &v.js_value;
quote! {
#[wasm_bindgen(js_name = #js_value)]
#rust_name
}
})
.collect();
quote! {
#[wasm_bindgen]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum #name {
#(#variants,)*
}
}
}
fn numeric_enum_repr(decl: &NumericEnumDecl) -> TokenStream {
let min = decl.variants.iter().map(|v| v.value).min().unwrap_or(0);
let max = decl.variants.iter().map(|v| v.value).max().unwrap_or(0);
if min >= 0 && max <= u32::MAX as i64 {
quote! { u32 }
} else if min >= i32::MIN as i64 && max <= i32::MAX as i64 {
quote! { i32 }
} else {
quote! { i32 }
}
}
pub fn generate_numeric_enum(decl: &NumericEnumDecl) -> TokenStream {
let name = super::typemap::make_ident(&decl.name);
let repr = numeric_enum_repr(decl);
let has_negative = decl.variants.iter().any(|v| v.value < 0);
let variants: Vec<_> = decl
.variants
.iter()
.map(|v| {
let rust_name = super::typemap::make_ident(&v.rust_name);
let doc = crate::codegen::doc_tokens(&v.doc);
if has_negative {
let value = i32::try_from(v.value).unwrap_or({
v.value as i32
});
quote! {
#doc
#rust_name = #value
}
} else {
let value = u32::try_from(v.value).unwrap_or(v.value as u32);
quote! {
#doc
#rust_name = #value
}
}
})
.collect();
quote! {
#[wasm_bindgen]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(#repr)]
pub enum #name {
#(#variants,)*
}
}
}