cgp_component_macro_lib/getter_component/
parse.rs1use alloc::vec::Vec;
2
3use quote::ToTokens;
4use syn::spanned::Spanned;
5use syn::{parse_quote, Error, FnArg, Ident, ItemTrait, ReturnType, TraitItem, Type};
6
7use crate::derive_component::replace_self_type::replace_self_type;
8use crate::getter_component::getter_field::GetterField;
9
10pub fn parse_getter_fields(
11 context_type: &Ident,
12 consumer_trait: &ItemTrait,
13) -> syn::Result<Vec<GetterField>> {
14 if !consumer_trait.generics.params.is_empty() {
15 return Err(Error::new(
16 consumer_trait.generics.params.span(),
17 "getter trait cannot contain generic parameters",
18 ));
19 }
20
21 let mut fields = Vec::new();
22
23 for item in consumer_trait.items.iter() {
24 match item {
25 TraitItem::Fn(method) => {
26 let signature = &method.sig;
27
28 if signature.constness.is_some() {
29 return Err(Error::new(
30 signature.constness.span(),
31 "getter method must not be const fn",
32 ));
33 }
34
35 if signature.asyncness.is_some() {
36 return Err(Error::new(
37 signature.asyncness.span(),
38 "getter method must not be async fn",
39 ));
40 }
41
42 if signature.unsafety.is_some() {
43 return Err(Error::new(
44 signature.unsafety.span(),
45 "getter method must not be unsafe fn",
46 ));
47 }
48
49 if !signature.generics.params.is_empty() {
50 return Err(Error::new(
51 signature.generics.params.span(),
52 "getter method must not contain generic param",
53 ));
54 }
55
56 if signature.generics.where_clause.is_some() {
57 return Err(Error::new(
58 signature.generics.where_clause.span(),
59 "getter method must not contain where clause",
60 ));
61 }
62
63 let field_name = signature.ident.clone();
64
65 let [arg]: [&FnArg; 1] = signature
66 .inputs
67 .iter()
68 .collect::<Vec<&FnArg>>()
69 .try_into()
70 .map_err(|_| {
71 Error::new(
72 signature.inputs.span(),
73 "getter method must contain exactly one `&self` argument",
74 )
75 })?;
76
77 let field_mut = match arg {
78 FnArg::Receiver(receiver) => {
79 if receiver.reference.is_none() {
80 return Err(Error::new(
81 receiver.span(),
82 "first argument to getter method must be a reference to self, i.e. `&self`"
83 ));
84 }
85
86 receiver.mutability
87 }
88 _ => {
89 return Err(Error::new(
90 arg.span(),
91 "first argument to getter method must be `&self`",
92 ))
93 }
94 };
95
96 let field_type: Type = match &signature.output {
97 ReturnType::Default => parse_quote!(()),
98 ReturnType::Type(_, ty) => {
99 let ty = ty.as_ref().clone();
100 match &ty {
101 Type::Reference(type_ref) => {
102 if type_ref.mutability.is_some() != field_mut.is_some() {
103 return Err(Error::new(
104 type_ref.span(),
105 "return type have the same mutability as the self reference",
106 ));
107 }
108
109 type_ref.elem.as_ref().clone()
110 }
111 _ => {
112 return Err(Error::new(
113 ty.span(),
114 "return type must be a reference",
115 ))
116 }
117 }
118 }
119 };
120
121 let provider_type: Type = syn::parse2(replace_self_type(
122 field_type.to_token_stream(),
123 context_type,
124 &Vec::new(),
125 ))?;
126
127 fields.push(GetterField {
128 field_name,
129 field_type,
130 provider_type,
131 field_mut,
132 })
133 }
134 _ => {
135 return Err(Error::new(
136 item.span(),
137 "getter trait can only contain getter methods",
138 ))
139 }
140 }
141 }
142
143 Ok(fields)
144}