use proc_macro2::Literal;
use quote::quote;
use syn::{Data, Fields};
pub fn derive(input: syn::DeriveInput) -> proc_macro2::TokenStream {
let enum_name = &input.ident;
let data = match &input.data {
Data::Enum(e) => e,
_ => panic!("Cannot derive for non-enum type"),
};
let cases = data.variants.iter()
.map(|variant| {
let ident = &variant.ident;
let variant_str = Literal::string(&ident.to_string());
let fields = match &variant.fields {
Fields::Named(fields) => {
let mapped = fields.named.iter().map(|field| {
let name = match &field.ident {
Some(name) => name,
None => panic!("Named fields should have names"),
};
let ty = &field.ty;
quote!( #name: #ty::default() )
});
quote!( { #(#mapped),* } )
},
Fields::Unnamed(fields) => {
let mapped = fields.unnamed.iter().map(|field| &field.ty );
quote!{ ( #(#mapped::default()),* ) }
},
Fields::Unit => quote!(),
};
quote! { #variant_str => Ok(#enum_name::#ident #fields) }
});
quote! {
impl std::str::FromStr for #enum_name {
type Err = ::derive_enum::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
#(#cases,)*
_ => Err(derive_enum::Error::NoSuchEnum),
}
}
}
}
}