cgp-macro-lib 0.7.0

Context-generic programming core component macros implemented as a library.
Documentation
use quote::{ToTokens, quote};
use syn::{Generics, Ident, ItemFn, ItemTrait, TraitItemFn, parse_quote, parse2};

use crate::cgp_fn::{FunctionAttributes, UseTypeSpec, substitute_abstract_types};

pub fn derive_item_trait(
    trait_ident: &Ident,
    item_fn: &ItemFn,
    generics: &Generics,
    attributes: &FunctionAttributes,
) -> syn::Result<ItemTrait> {
    let trait_item_fn = TraitItemFn {
        attrs: item_fn.attrs.clone(),
        sig: item_fn.sig.clone(),
        default: None,
        semi_token: None,
    };

    let mut item_trait: ItemTrait = parse2(quote! {
        pub trait #trait_ident {
            #trait_item_fn
        }
    })?;

    item_trait.generics = generics.clone();
    item_trait.generics.where_clause = None;

    item_trait.supertraits.extend(attributes.extend.clone());

    if !attributes.extend_where.is_empty() {
        item_trait
            .generics
            .make_where_clause()
            .predicates
            .extend(attributes.extend_where.clone());
    }

    if !attributes.use_type.is_empty() {
        item_trait = expand_use_type_attributes_on_trait(&item_trait, &attributes.use_type)?;
    }

    Ok(item_trait)
}

pub fn expand_use_type_attributes_on_trait(
    item_trait: &ItemTrait,
    use_type_specs: &[UseTypeSpec],
) -> syn::Result<ItemTrait> {
    let mut item_trait: ItemTrait = parse2(substitute_abstract_types(
        use_type_specs,
        item_trait.to_token_stream(),
    ))?;

    for use_type in use_type_specs.iter() {
        if use_type.context_type != parse_quote! { Self } {
            continue;
        }

        item_trait
            .supertraits
            .push(parse2(use_type.trait_path.to_token_stream())?);
    }

    Ok(item_trait)
}