use std::collections::HashMap;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use syn::{parse_quote, ItemEnum, ItemTrait};
use crate::generate::enum_conversion::generate_variant_conversions;
use crate::generate_delegation::MacroContext;
use crate::input::AssociatedTypeUnification;
pub(crate) fn generate_associated_type_enum_names(
parsed_trait: &ItemTrait,
associated_type_config: &HashMap<Ident, AssociatedTypeUnification>,
parsed_enum: &ItemEnum,
) -> HashMap<Ident, Ident> {
associated_type_config
.iter()
.filter(|(_, config)| matches!(config, AssociatedTypeUnification::EnumWrap))
.map(|(associated_type, _)| {
let enum_name = format_ident!(
"{}_for_{}_associated_type_{}_generated_by_enum_delegate",
parsed_trait.ident,
parsed_enum.ident,
associated_type
);
(associated_type.clone(), enum_name)
})
.collect()
}
pub(crate) fn generate_enum_definitions(context: &MacroContext) -> TokenStream {
let associated_type_enum_names = &context.associated_type_enum_names;
let enum_definitions = associated_type_enum_names
.iter()
.map(|(associated_type, enum_name)| generate_enum(context, associated_type, enum_name));
quote! {
#(#enum_definitions)*
}
}
fn generate_enum(
context: &MacroContext,
associated_type: &Ident,
enum_name: &Ident,
) -> TokenStream {
let trait_path = context.trait_path;
let enum_variants = context.parsed_enum.variants().iter().map(|variant| {
let variant_name = &variant.name;
let variant_type = &variant.type_;
quote! {
#variant_name(<#variant_type as #trait_path>::#associated_type)
}
});
let enum_conversions = context.parsed_enum.variants().iter().map(|variant| {
let variant_name = &variant.name;
let variant_type = &variant.type_;
generate_variant_conversions(
&parse_quote!(#enum_name),
variant_name,
&parse_quote!(<#variant_type as #trait_path>::#associated_type),
)
});
quote! {
#[allow(non_camel_case_types)]
enum #enum_name {
#(#enum_variants,)*
}
#(#enum_conversions)*
}
}