use crate::utils::snakecase;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::{Fields, Ident, Variant};
pub fn impl_functional_constructors(
name: &Ident,
variants: &Punctuated<Variant, Comma>,
) -> TokenStream {
use syn::{FieldsNamed, FieldsUnnamed};
let mut constructors = TokenStream::new();
variants.iter().for_each(
|Variant {
ident: variant_name,
fields: variant_fields,
..
}| {
let constructor_name = Ident::new(&snakecase(variant_name), Span::call_site());
let func = match variant_fields {
Fields::Named(FieldsNamed { named, .. }) => {
let mut field_names = Vec::new();
let mut field_types = Vec::new();
named.iter().for_each(|i| {
if let Some(ident) = &i.ident {
field_names.push(ident);
}
field_types.push(&i.ty);
});
let constructor = quote! {
pub fn #constructor_name(#(#field_names: #field_types),*) -> Self {
Self::#variant_name { #(#field_names),* }
}
};
constructor
}
Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
let mut field_names = Vec::new();
let mut field_types = Vec::new();
unnamed.iter().enumerate().for_each(|(i, field)| {
field_names.push(Ident::new(&format!("field_{}", i), Span::call_site()));
field_types.push(&field.ty);
});
let constructor = quote! {
pub fn #constructor_name(#(#field_names: #field_types),*) -> Self {
Self::#variant_name(#(#field_names),*)
}
};
constructor
}
Fields::Unit => {
let constructor = quote! {
pub fn #constructor_name() -> Self {
Self::#variant_name
}
};
constructor
}
};
constructors.extend(func);
},
);
quote! {
impl #name {
#constructors
}
}
}