cgp-macro-lib 0.6.1

Context-generic programming core component macros implemented as a library.
Documentation
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Ident, ItemImpl, ItemStruct, parse2};

use crate::derive_context::{derive_delegate_preset, derive_has_components};
use crate::parse::ContextSpec;

pub fn cgp_context(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
    let context_struct: ItemStruct = syn::parse2(body)?;

    let context_spec: ContextSpec = if !attr.is_empty() {
        syn::parse2(attr)?
    } else {
        let provider_name = Ident::new(
            &format!("{}Components", context_struct.ident),
            context_struct.ident.span(),
        );

        ContextSpec {
            provider_name,
            provider_generics: None,
            preset: None,
        }
    };

    let provider_name = &context_spec.provider_name;
    let provider_generics = &context_spec.provider_generics;

    let provider_phantom = match provider_generics {
        Some(generics) => {
            let params = &generics.generics.params;
            quote! { ( ::core::marker::PhantomData<( #params )> ) }
        }
        None => quote! {},
    };

    let provider_struct: ItemStruct =
        parse2(quote!( pub struct #provider_name #provider_generics #provider_phantom; ))?;

    let has_components_impl: ItemImpl =
        derive_has_components(provider_name, provider_generics, &context_struct)?;

    let base_derived = quote! {
        #context_struct

        #provider_struct

        #has_components_impl
    };

    match &context_spec.preset {
        Some(preset) => {
            let (delegate_impl, is_provider_impl) =
                derive_delegate_preset(provider_name, provider_generics, preset)?;

            Ok(quote! {
                #base_derived

                #delegate_impl

                #is_provider_impl
            })
        }
        _ => Ok(base_derived),
    }
}