cgp_macro_lib/entrypoints/
cgp_getter.rs1use std::collections::BTreeMap;
2use std::collections::btree_map::Entry;
3
4use proc_macro2::TokenStream;
5use quote::{ToTokens, quote};
6use syn::{Ident, ItemTrait, Type, parse_quote, parse2};
7
8use crate::derive_component::derive_component_with_ast;
9use crate::derive_getter::{
10 GetterField, derive_use_field_impl, derive_use_fields_impl, derive_with_provider_impl,
11 parse_getter_fields,
12};
13use crate::derive_provider::derive_is_provider_for;
14use crate::parse::{ComponentSpec, Entries};
15
16pub fn cgp_getter(attr: TokenStream, body: TokenStream) -> syn::Result<TokenStream> {
17 let mut entries = if let Ok(provider_ident) = parse2::<Ident>(attr.clone()) {
18 BTreeMap::from([("provider".to_owned(), provider_ident.to_token_stream())])
19 } else {
20 parse2::<Entries>(attr)?.entries
21 };
22
23 let consumer_trait: ItemTrait = syn::parse2(body)?;
24
25 let provider_entry = entries.entry("provider".to_owned());
26
27 if let Entry::Vacant(entry) = provider_entry {
28 let consumer_name = consumer_trait.ident.to_string();
29 if let Some(field_name) = consumer_name.strip_prefix("Has")
30 && !field_name.is_empty()
31 {
32 let provider_name =
33 Ident::new(&format!("{field_name}Getter"), consumer_trait.ident.span());
34 entry.insert(parse2(provider_name.to_token_stream())?);
35 }
36 }
37
38 let spec = ComponentSpec::from_entries(&entries)?;
39
40 let derived_component = derive_component_with_ast(&spec, consumer_trait.clone())?;
41
42 let fields = parse_getter_fields(&spec.context_type, &consumer_trait)?;
43
44 let use_fields_impl =
45 derive_use_fields_impl(&spec, &derived_component.provider_trait, &fields)?;
46
47 let component_name_type: Type = {
48 let component_name = &spec.component_name;
49 let component_params = &spec.component_params;
50 parse_quote!( #component_name < #component_params > )
51 };
52
53 let is_provider_use_fields_impl =
54 derive_is_provider_for(&component_name_type, &use_fields_impl)?;
55
56 let m_field: Option<[GetterField; 1]> = fields.try_into().ok();
57
58 let mut derived = quote! {
59 #derived_component
60
61 #use_fields_impl
62
63 #is_provider_use_fields_impl
64 };
65
66 if let Some([field]) = m_field {
67 let use_field_impl =
68 derive_use_field_impl(&spec, &derived_component.provider_trait, &field)?;
69 let is_provider_use_field_impl =
70 derive_is_provider_for(&component_name_type, &use_field_impl)?;
71
72 let use_provider_impl =
73 derive_with_provider_impl(&spec, &derived_component.provider_trait, &field)?;
74 let is_provider_use_provider_impl =
75 derive_is_provider_for(&component_name_type, &use_provider_impl)?;
76
77 derived.extend(quote! {
78 #use_field_impl
79 #is_provider_use_field_impl
80
81 #use_provider_impl
82 #is_provider_use_provider_impl
83 });
84 }
85
86 Ok(derived)
87}