educe/trait_handlers/partial_eq/models/field_attribute.rs
1use quote::ToTokens;
2use syn::{Attribute, Lit, Meta, NestedMeta};
3
4use super::super::super::create_path_string_from_lit_str;
5use crate::{panic, Trait};
6
7#[derive(Debug, Clone)]
8pub struct FieldAttribute {
9 pub ignore: bool,
10 pub compare_method: Option<String>,
11 pub compare_trait: Option<String>,
12}
13
14#[derive(Debug, Clone)]
15pub struct FieldAttributeBuilder {
16 pub enable_ignore: bool,
17 pub enable_impl: bool,
18}
19
20impl FieldAttributeBuilder {
21 #[allow(clippy::wrong_self_convention)]
22 pub fn from_partial_eq_meta(&self, meta: &Meta) -> FieldAttribute {
23 let mut ignore = false;
24
25 let mut compare_method = None;
26 let mut compare_trait = None;
27
28 let correct_usage_for_partial_eq_attribute = {
29 let mut usage = vec![];
30
31 if self.enable_ignore {
32 usage.push(stringify!(#[educe(PartialEq = false)]));
33 usage.push(stringify!(#[educe(PartialEq(false))]));
34 }
35
36 usage
37 };
38
39 let correct_usage_for_ignore = {
40 let usage = vec![stringify!(#[educe(PartialEq(ignore))])];
41
42 usage
43 };
44
45 let correct_usage_for_impl = {
46 let usage = vec![
47 stringify!(#[educe(PartialEq(method = "path_to_method"))]),
48 stringify!(#[educe(PartialEq(trait = "path_to_trait"))]),
49 stringify!(#[educe(PartialEq(trait = "path_to_trait", method = "path_to_method_in_trait"))]),
50 stringify!(#[educe(PartialEq(method("path_to_method")))]),
51 stringify!(#[educe(PartialEq(trait("path_to_trait")))]),
52 stringify!(#[educe(PartialEq(trait("path_to_trait"), method("path_to_method_in_trait")))]),
53 ];
54
55 usage
56 };
57
58 match meta {
59 Meta::List(list) => {
60 let mut ignore_is_set = false;
61
62 for p in list.nested.iter() {
63 match p {
64 NestedMeta::Meta(meta) => {
65 let meta_name = meta.path().into_token_stream().to_string();
66
67 match meta_name.as_str() {
68 "ignore" => {
69 if !self.enable_ignore {
70 panic::unknown_parameter("PartialEq", meta_name.as_str());
71 }
72
73 match meta {
74 Meta::Path(_) => {
75 if ignore_is_set {
76 panic::reset_parameter(meta_name.as_str());
77 }
78
79 ignore_is_set = true;
80
81 ignore = true;
82 },
83 _ => panic::parameter_incorrect_format(
84 meta_name.as_str(),
85 &correct_usage_for_ignore,
86 ),
87 }
88 },
89 "method" => {
90 if !self.enable_impl {
91 panic::unknown_parameter("PartialEq", meta_name.as_str());
92 }
93
94 match meta {
95 Meta::List(list) => {
96 for p in list.nested.iter() {
97 match p {
98 NestedMeta::Lit(Lit::Str(s)) => {
99 if compare_method.is_some() {
100 panic::reset_parameter(
101 meta_name.as_str(),
102 );
103 }
104
105 let s = create_path_string_from_lit_str(s);
106
107 if let Some(s) = s {
108 compare_method = Some(s);
109 } else {
110 panic::empty_parameter(
111 meta_name.as_str(),
112 );
113 }
114 },
115 _ => panic::parameter_incorrect_format(
116 meta_name.as_str(),
117 &correct_usage_for_impl,
118 ),
119 }
120 }
121 },
122 Meta::NameValue(named_value) => {
123 let lit = &named_value.lit;
124
125 match lit {
126 Lit::Str(s) => {
127 if compare_method.is_some() {
128 panic::reset_parameter(meta_name.as_str());
129 }
130
131 let s = create_path_string_from_lit_str(s);
132
133 if let Some(s) = s {
134 compare_method = Some(s);
135 } else {
136 panic::empty_parameter(meta_name.as_str());
137 }
138 },
139 _ => panic::parameter_incorrect_format(
140 meta_name.as_str(),
141 &correct_usage_for_impl,
142 ),
143 }
144 },
145 _ => panic::parameter_incorrect_format(
146 meta_name.as_str(),
147 &correct_usage_for_impl,
148 ),
149 }
150 },
151 "trait" => {
152 if !self.enable_impl {
153 panic::unknown_parameter("PartialEq", meta_name.as_str());
154 }
155
156 match meta {
157 Meta::List(list) => {
158 for p in list.nested.iter() {
159 match p {
160 NestedMeta::Lit(Lit::Str(s)) => {
161 if compare_trait.is_some() {
162 panic::reset_parameter(
163 meta_name.as_str(),
164 );
165 }
166
167 let s = create_path_string_from_lit_str(s);
168
169 if let Some(s) = s {
170 compare_trait = Some(s);
171 } else {
172 panic::empty_parameter(
173 meta_name.as_str(),
174 );
175 }
176 },
177 _ => panic::parameter_incorrect_format(
178 meta_name.as_str(),
179 &correct_usage_for_impl,
180 ),
181 }
182 }
183 },
184 Meta::NameValue(named_value) => {
185 let lit = &named_value.lit;
186
187 match lit {
188 Lit::Str(s) => {
189 if compare_trait.is_some() {
190 panic::reset_parameter(meta_name.as_str());
191 }
192
193 let s = create_path_string_from_lit_str(s);
194
195 if let Some(s) = s {
196 compare_trait = Some(s);
197 } else {
198 panic::empty_parameter(meta_name.as_str());
199 }
200 },
201 _ => panic::parameter_incorrect_format(
202 meta_name.as_str(),
203 &correct_usage_for_impl,
204 ),
205 }
206 },
207 _ => panic::parameter_incorrect_format(
208 meta_name.as_str(),
209 &correct_usage_for_impl,
210 ),
211 }
212 },
213 _ => panic::unknown_parameter("PartialEq", meta_name.as_str()),
214 }
215 },
216 _ => panic::attribute_incorrect_format(
217 "PartialEq",
218 &correct_usage_for_partial_eq_attribute,
219 ),
220 }
221 }
222 },
223 _ => panic::attribute_incorrect_format(
224 "PartialEq",
225 &correct_usage_for_partial_eq_attribute,
226 ),
227 }
228
229 if compare_trait.is_some() && compare_method.is_none() {
230 compare_method = Some("eq".to_string());
231 }
232
233 FieldAttribute {
234 ignore,
235 compare_method,
236 compare_trait,
237 }
238 }
239
240 #[allow(clippy::wrong_self_convention)]
241 pub fn from_attributes(self, attributes: &[Attribute], traits: &[Trait]) -> FieldAttribute {
242 let mut result = None;
243
244 for attribute in attributes.iter() {
245 if attribute.path.is_ident("educe") {
246 let meta = attribute.parse_meta().unwrap();
247
248 match meta {
249 Meta::List(list) => {
250 for p in list.nested.iter() {
251 match p {
252 NestedMeta::Meta(meta) => {
253 let meta_name = meta.path().into_token_stream().to_string();
254
255 let t = Trait::from_str(meta_name);
256
257 if traits.binary_search(&t).is_err() {
258 panic::trait_not_used(t);
259 }
260
261 if t == Trait::PartialEq {
262 if result.is_some() {
263 panic::reuse_a_trait(t);
264 }
265
266 result = Some(self.from_partial_eq_meta(meta));
267 }
268 },
269 _ => panic::educe_format_incorrect(),
270 }
271 }
272 },
273 _ => panic::educe_format_incorrect(),
274 }
275 }
276 }
277
278 result.unwrap_or(FieldAttribute {
279 ignore: false,
280 compare_method: None,
281 compare_trait: None,
282 })
283 }
284}