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