cgp_component_macro_lib/derive_component/
provider_impl.rs

1use alloc::boxed::Box;
2use alloc::vec::Vec;
3
4use proc_macro2::Span;
5use syn::punctuated::Punctuated;
6use syn::token::{Brace, Comma, For, Impl, Plus};
7use syn::{
8    parse_quote, GenericParam, Ident, ImplItem, ItemImpl, ItemTrait, Path, TraitItem,
9    TypeParamBound,
10};
11
12use crate::derive_component::delegate_fn::derive_delegated_fn_impl;
13use crate::derive_component::delegate_type::derive_delegate_type_impl;
14
15pub fn derive_provider_impl(
16    provider_trait: &ItemTrait,
17    component_name: &Ident,
18    component_params: &Punctuated<Ident, Comma>,
19) -> ItemImpl {
20    let provider_name = &provider_trait.ident;
21
22    let component_type = Ident::new("Component", Span::call_site());
23
24    let provider_generic_args = {
25        let mut generic_args: Punctuated<Ident, Comma> = Punctuated::new();
26
27        for param in provider_trait.generics.params.iter() {
28            match param {
29                GenericParam::Type(ty) => {
30                    generic_args.push(ty.ident.clone());
31                }
32                GenericParam::Const(arg) => {
33                    generic_args.push(arg.ident.clone());
34                }
35                GenericParam::Lifetime(_life) => {
36                    unimplemented!()
37                }
38            }
39        }
40
41        generic_args
42    };
43
44    let impl_generics = {
45        let mut impl_generics = provider_trait.generics.clone();
46
47        impl_generics
48            .params
49            .insert(0, parse_quote!(#component_type));
50
51        {
52            let delegate_constraint: Punctuated<TypeParamBound, Plus> = parse_quote! {
53                DelegateComponent< #component_name < #component_params > >
54            };
55
56            let provider_constraint: Punctuated<TypeParamBound, Plus> = parse_quote! {
57                #provider_name < #provider_generic_args >
58            };
59
60            match &mut impl_generics.where_clause {
61                Some(where_clause) => {
62                    where_clause.predicates.push(parse_quote! {
63                        #component_type : #delegate_constraint
64                    });
65
66                    where_clause.predicates.push(parse_quote! {
67                        #component_type :: Delegate : #provider_constraint
68                    });
69                }
70                _ => {
71                    impl_generics.where_clause = Some(parse_quote! {
72                        where
73                            #component_type : #delegate_constraint,
74                            #component_type :: Delegate : #provider_constraint
75                    });
76                }
77            }
78        }
79
80        impl_generics
81    };
82
83    let mut impl_items: Vec<ImplItem> = Vec::new();
84
85    for trait_item in provider_trait.items.iter() {
86        match trait_item {
87            TraitItem::Fn(trait_fn) => {
88                let impl_fn = derive_delegated_fn_impl(
89                    &trait_fn.sig,
90                    &parse_quote!(#component_type :: Delegate),
91                );
92
93                impl_items.push(ImplItem::Fn(impl_fn))
94            }
95            TraitItem::Type(trait_type) => {
96                let type_name = &trait_type.ident;
97                let type_generics = {
98                    let mut type_generics = trait_type.generics.clone();
99                    type_generics.where_clause = None;
100
101                    for param in &mut type_generics.params {
102                        if let GenericParam::Type(type_param) = param {
103                            type_param.bounds.clear();
104                        }
105                    }
106
107                    type_generics
108                };
109
110                let impl_type = derive_delegate_type_impl(
111                    trait_type,
112                    parse_quote!(
113                        < #component_type :: Delegate as #provider_name < #provider_generic_args > > :: #type_name #type_generics
114                    ),
115                );
116
117                impl_items.push(ImplItem::Type(impl_type));
118            }
119            _ => {}
120        }
121    }
122
123    let trait_path: Path = parse_quote!( #provider_name < #provider_generic_args > );
124
125    ItemImpl {
126        attrs: provider_trait.attrs.clone(),
127        defaultness: None,
128        unsafety: provider_trait.unsafety,
129        impl_token: Impl::default(),
130        generics: impl_generics,
131        trait_: Some((None, trait_path, For::default())),
132        self_ty: Box::new(parse_quote!(#component_type)),
133        brace_token: Brace::default(),
134        items: impl_items,
135    }
136}