enum_delegate_lib 0.2.0

Internal macro implementations for enum_delegate - use to implement your own macros
Documentation
//! Code generation for associated type helper enum definitions

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;

/// For each associated type that needs to be wrapped in an enum, generate a name for the enum
///
/// Returns a map from the associated type's name to the corresponding enum's name
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()
}

/// Generate enum definitions required for the associated types
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)*
    }
}