cgp_macro_lib/entrypoints/
cgp_context.rs

1use proc_macro2::TokenStream;
2use quote::quote;
3use syn::{Ident, ItemImpl, ItemStruct, parse2};
4
5use crate::derive_context::{derive_delegate_preset, derive_has_components};
6use crate::parse::ContextSpec;
7
8pub fn cgp_context(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
9    let context_struct: ItemStruct = syn::parse2(body)?;
10
11    let context_spec: ContextSpec = if !attr.is_empty() {
12        syn::parse2(attr)?
13    } else {
14        let provider_name = Ident::new(
15            &format!("{}Components", context_struct.ident),
16            context_struct.ident.span(),
17        );
18
19        ContextSpec {
20            provider_name,
21            provider_generics: None,
22            preset: None,
23        }
24    };
25
26    let provider_name = &context_spec.provider_name;
27    let provider_generics = &context_spec.provider_generics;
28
29    let provider_phantom = match provider_generics {
30        Some(generics) => {
31            let params = &generics.generics.params;
32            quote! { ( ::core::marker::PhantomData<( #params )> ) }
33        }
34        None => quote! {},
35    };
36
37    let provider_struct: ItemStruct =
38        parse2(quote!( pub struct #provider_name #provider_generics #provider_phantom; ))?;
39
40    let has_components_impl: ItemImpl =
41        derive_has_components(provider_name, provider_generics, &context_struct)?;
42
43    let base_derived = quote! {
44        #context_struct
45
46        #provider_struct
47
48        #has_components_impl
49    };
50
51    match &context_spec.preset {
52        Some(preset) => {
53            let (delegate_impl, is_provider_impl) =
54                derive_delegate_preset(provider_name, provider_generics, preset)?;
55
56            Ok(quote! {
57                #base_derived
58
59                #delegate_impl
60
61                #is_provider_impl
62            })
63        }
64        _ => Ok(base_derived),
65    }
66}