cgp_component_macro_lib/derive_component/
consumer_impl.rs1use 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}