cgp_component_macro_lib/derive_component/
consumer_impl.rs

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