cgp_component_macro_lib/getter_component/
parse.rs

1use 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}