1use proc_macro2::TokenStream;
31use quote::quote;
32
33use crate::ir::{NumericEnumDecl, StringEnumDecl};
34
35pub fn generate_string_enum(decl: &StringEnumDecl) -> TokenStream {
37 let name = super::typemap::make_ident(&decl.name);
38
39 let variants: Vec<_> = decl
40 .variants
41 .iter()
42 .map(|v| {
43 let rust_name = super::typemap::make_ident(&v.rust_name);
44 let js_value = &v.js_value;
45 quote! {
46 #[wasm_bindgen(js_name = #js_value)]
47 #rust_name
48 }
49 })
50 .collect();
51
52 quote! {
53 #[wasm_bindgen]
54 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
55 pub enum #name {
56 #(#variants,)*
57 }
58 }
59}
60
61fn numeric_enum_repr(decl: &NumericEnumDecl) -> TokenStream {
63 let min = decl.variants.iter().map(|v| v.value).min().unwrap_or(0);
64 let max = decl.variants.iter().map(|v| v.value).max().unwrap_or(0);
65
66 if min >= 0 && max <= u32::MAX as i64 {
67 quote! { u32 }
68 } else if min >= i32::MIN as i64 && max <= i32::MAX as i64 {
69 quote! { i32 }
70 } else {
71 quote! { i32 }
74 }
75}
76
77pub fn generate_numeric_enum(decl: &NumericEnumDecl) -> TokenStream {
79 let name = super::typemap::make_ident(&decl.name);
80 let repr = numeric_enum_repr(decl);
81
82 let has_negative = decl.variants.iter().any(|v| v.value < 0);
83
84 let variants: Vec<_> = decl
85 .variants
86 .iter()
87 .map(|v| {
88 let rust_name = super::typemap::make_ident(&v.rust_name);
89 let doc = crate::codegen::doc_tokens(&v.doc);
90 if has_negative {
91 let value = i32::try_from(v.value).unwrap_or({
92 v.value as i32
95 });
96 quote! {
97 #doc
98 #rust_name = #value
99 }
100 } else {
101 let value = u32::try_from(v.value).unwrap_or(v.value as u32);
102 quote! {
103 #doc
104 #rust_name = #value
105 }
106 }
107 })
108 .collect();
109
110 quote! {
111 #[wasm_bindgen]
112 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
113 #[repr(#repr)]
114 pub enum #name {
115 #(#variants,)*
116 }
117 }
118}