use indexmap::IndexMap;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{DataEnum, DataStruct, Ident, Pat, Variant};
use crate::types::{
DeriveInput, ResolutionMode, abs_helper_path, enum_variant_to_pattern,
struct_to_pattern,
};
fn enum_impl(
who: &Ident,
pattern_lut: &IndexMap<Variant, Pat>,
resolution_lut: &IndexMap<Variant, ResolutionMode>,
) -> TokenStream {
let pat = pattern_lut.values();
let resolution = resolution_lut.values();
let fatality_trait =
abs_helper_path(Ident::new("Fatality", who.span()), who.span());
quote! {
#[automatically_derived]
impl #fatality_trait for #who {
fn is_fatal(&self) -> bool {
match self {
#( #pat => #resolution, )*
}
}
}
}
}
pub(crate) fn enum_gen(
mut item: DeriveInput<DataEnum>,
) -> syn::Result<TokenStream> {
let mut resolution_lut = IndexMap::new();
let mut pattern_lut = IndexMap::new();
for variant in item.data.variants.iter_mut() {
let resolution_mode =
ResolutionMode::extract_from_variant_attrs(variant)?;
let (pattern, resolution_mode) =
enum_variant_to_pattern(variant, resolution_mode)?;
if let ResolutionMode::Forward(_, None) = resolution_mode {
unreachable!("Must have an ident. qed")
}
resolution_lut.insert(variant.clone(), resolution_mode);
pattern_lut.insert(variant.clone(), pattern);
}
Ok(enum_impl(&item.ident, &pattern_lut, &resolution_lut))
}
fn struct_impl(who: &Ident, resolution: &ResolutionMode) -> TokenStream {
let fatality_trait =
abs_helper_path(Ident::new("Fatality", who.span()), who.span());
let resolution = match resolution {
ResolutionMode::Forward(_fwd, field) => {
let field = field
.as_ref()
.expect("Ident must be filled at this point. qed");
quote! {
#fatality_trait :: is_fatal( & self. #field )
}
}
rm => quote! {
#rm
},
};
quote! {
#[automatically_derived]
impl #fatality_trait for #who {
fn is_fatal(&self) -> bool {
#resolution
}
}
}
}
pub(crate) fn struct_gen(
mut item: DeriveInput<DataStruct>,
) -> syn::Result<proc_macro2::TokenStream> {
let resolution_mode = ResolutionMode::extract_from_struct_attrs(&mut item)?;
let (_pat, resolution_mode) = struct_to_pattern(&item, resolution_mode)?;
Ok(struct_impl(&item.ident, &resolution_mode))
}