1use std::{error::Error, iter};
2
3use either_n::Either3;
4use proc_macro2::{Ident, Span, TokenStream};
5use quote::{format_ident, quote, ToTokens};
6use syn::{parse_quote, Attribute, Expr, ExprUnary, Path, Token, Type};
7
8use crate::{HasAttributes, TypeOfSelf};
9
10pub enum Fields {
13 Named(Vec<NamedField>, Vec<Attribute>),
15 Unnamed(Vec<UnnamedField>, Vec<Attribute>),
17 Unit(Vec<Attribute>),
19}
20
21impl Fields {
22 pub fn get_field_attributes(&self) -> &[Attribute] {
23 match self {
24 Fields::Named(_, attributes)
25 | Fields::Unnamed(_, attributes)
26 | Fields::Unit(attributes) => attributes,
27 }
28 }
29
30 pub fn fields_iterator(&self) -> impl ExactSizeIterator<Item = NamedOrUnnamedField<'_>> {
31 match self {
32 Fields::Named(fields, ..) => {
33 Either3::One(fields.iter().map(NamedOrUnnamedField::Named))
34 }
35 Fields::Unnamed(fields, ..) => {
36 Either3::Two(fields.iter().map(NamedOrUnnamedField::Unnamed))
37 }
38 Fields::Unit(..) => Either3::Three(iter::empty()),
39 }
40 }
41
42 pub fn fields_iterator_mut(
43 &mut self,
44 ) -> impl ExactSizeIterator<Item = NamedOrUnnamedFieldMut<'_>> {
45 match self {
46 Fields::Named(fields, ..) => {
47 Either3::One(fields.iter_mut().map(NamedOrUnnamedFieldMut::Named))
48 }
49 Fields::Unnamed(fields, ..) => {
50 Either3::Two(fields.iter_mut().map(NamedOrUnnamedFieldMut::Unnamed))
51 }
52 Fields::Unit(..) => Either3::Three(iter::empty()),
53 }
54 }
55
56 pub fn to_pattern(&self, path: Path, type_of_self: TypeOfSelf) -> TokenStream {
57 Self::to_pattern_with_config(self, path, type_of_self, "")
58 }
59
60 pub fn to_pattern_with_config(
61 &self,
62 path: Path,
63 type_of_self: TypeOfSelf,
64 name_postfix: &'static str,
65 ) -> TokenStream {
66 match self {
67 Fields::Named(fields, ..) => {
68 let fields_pattern = fields
69 .iter()
70 .map(|field| field.get_pattern_with_config(type_of_self, name_postfix));
71 quote!(#path { #(#fields_pattern),* })
72 }
73 Fields::Unnamed(fields, ..) => {
74 let fields_pattern = fields
75 .iter()
76 .map(|field| field.get_pattern_with_config(type_of_self, name_postfix));
77 quote!(#path(#(#fields_pattern),*))
78 }
79 Fields::Unit(..) => quote!(#path),
80 }
81 }
82
83 pub fn to_constructor<'b>(
84 &'b self,
85 generator: impl Fn(NamedOrUnnamedField<'b>) -> Result<Expr, Box<dyn Error>>,
86 constructor: Path,
87 ) -> Result<Expr, Box<dyn Error>> {
88 match self {
89 Fields::Named(fields, ..) => {
90 let arguments = fields
91 .iter()
92 .map(|field| {
93 generator(NamedOrUnnamedField::Named(field)).map(|value| {
94 let field_name = field.name.clone();
95 quote! { #field_name: #value }
96 })
97 })
98 .collect::<Result<Vec<_>, _>>()?;
99 Ok(parse_quote! { #constructor { #(#arguments),* } })
100 }
101 Fields::Unnamed(fields, ..) => {
102 let arguments = fields
103 .iter()
104 .map(|field| generator(NamedOrUnnamedField::Unnamed(field)))
105 .collect::<Result<Vec<_>, _>>()?;
106 Ok(parse_quote! { #constructor (#(#arguments),*) })
107 }
108 Fields::Unit(..) => Ok(parse_quote! { #constructor }),
109 }
110 }
111
112 pub fn get_field_by_member(&self, member: syn::Member) -> Option<NamedOrUnnamedField> {
114 match self {
115 Fields::Named(named, _) => {
116 if let syn::Member::Named(ident) = member {
117 named
118 .iter()
119 .find(|named| named.name == ident)
120 .map(NamedOrUnnamedField::Named)
121 } else {
122 None
123 }
124 }
125 Fields::Unnamed(unnamed, _) => {
126 if let syn::Member::Unnamed(idx) = member {
127 unnamed
128 .get(idx.index as usize)
129 .map(NamedOrUnnamedField::Unnamed)
130 } else {
131 None
132 }
133 }
134 Fields::Unit(_) => None,
135 }
136 }
137
138 pub fn get_field_by_member_mut(
140 &mut self,
141 member: syn::Member,
142 ) -> Option<NamedOrUnnamedFieldMut> {
143 match self {
144 Fields::Named(named, _) => {
145 if let syn::Member::Named(ident) = member {
146 named
147 .iter_mut()
148 .find(|named| named.name == ident)
149 .map(NamedOrUnnamedFieldMut::Named)
150 } else {
151 None
152 }
153 }
154 Fields::Unnamed(unnamed, _) => {
155 if let syn::Member::Unnamed(idx) = member {
156 unnamed
157 .get_mut(idx.index as usize)
158 .map(NamedOrUnnamedFieldMut::Unnamed)
159 } else {
160 None
161 }
162 }
163 Fields::Unit(_) => None,
164 }
165 }
166}
167
168pub(crate) fn syn_fields_to_fields(fields: syn::Fields, attributes: Vec<syn::Attribute>) -> Fields {
170 match fields {
171 syn::Fields::Named(named_fields) => {
172 let named_fields = named_fields
173 .named
174 .into_iter()
175 .enumerate()
176 .map(|(idx, field)| NamedField {
177 attrs: field.attrs,
178 name: field.ident.unwrap(),
179 ty: field.ty,
180 is_used: false,
181 used_for_trait: false,
182 idx,
183 })
184 .collect::<Vec<_>>();
185
186 Fields::Named(named_fields, attributes)
187 }
188 syn::Fields::Unnamed(unnamed_fields) => {
189 let fields = unnamed_fields
190 .unnamed
191 .into_iter()
192 .enumerate()
193 .map(|(idx, field)| UnnamedField {
194 idx,
195 attrs: field.attrs,
196 ty: field.ty,
197 is_used: false,
198 used_for_trait: false,
199 })
200 .collect::<Vec<_>>();
201
202 Fields::Unnamed(fields, attributes)
203 }
204 syn::Fields::Unit => Fields::Unit(attributes),
205 }
206}
207
208pub trait Field: HasAttributes {
210 #[cfg(feature = "field_is_type")]
212 fn is_type(&self, ty: &Type) -> bool {
213 self.get_type() == ty
214 }
215
216 fn get_type(&self) -> &Type;
217
218 fn get_pattern(&self, type_of_self: TypeOfSelf) -> TokenStream {
220 Self::get_pattern_with_config(self, type_of_self, "")
221 }
222
223 fn get_pattern_with_config(
225 &self,
226 type_of_self: TypeOfSelf,
227 name_postfix: &'static str,
228 ) -> TokenStream;
229
230 fn get_type_that_needs_constraint(&self) -> Option<Type>;
232}
233
234pub trait FieldMut: Field {
236 fn get_reference(&mut self) -> Expr {
240 Self::get_reference_with_config(self, true, "")
241 }
242
243 fn get_reference_with_config(
244 &mut self,
245 used_for_trait: bool,
246 name_postfix: &'static str,
247 ) -> Expr;
248}
249
250pub enum NamedOrUnnamedField<'a> {
252 Named(&'a NamedField),
253 Unnamed(&'a UnnamedField),
254}
255
256pub enum NamedOrUnnamedFieldMut<'a> {
258 Named(&'a mut NamedField),
259 Unnamed(&'a mut UnnamedField),
260}
261
262impl HasAttributes for NamedOrUnnamedField<'_> {
263 fn get_attributes(&self) -> &[Attribute] {
264 match self {
265 NamedOrUnnamedField::Named(named) => named.get_attributes(),
266 NamedOrUnnamedField::Unnamed(unnamed) => unnamed.get_attributes(),
267 }
268 }
269}
270
271impl Field for NamedOrUnnamedField<'_> {
272 fn get_type_that_needs_constraint(&self) -> Option<Type> {
273 match self {
274 NamedOrUnnamedField::Named(named) => named.get_type_that_needs_constraint(),
275 NamedOrUnnamedField::Unnamed(unnamed) => unnamed.get_type_that_needs_constraint(),
276 }
277 }
278
279 fn get_pattern_with_config(
280 &self,
281 type_of_self: TypeOfSelf,
282 name_postfix: &'static str,
283 ) -> TokenStream {
284 match self {
285 NamedOrUnnamedField::Named(named) => {
286 named.get_pattern_with_config(type_of_self, name_postfix)
287 }
288 NamedOrUnnamedField::Unnamed(unnamed) => {
289 unnamed.get_pattern_with_config(type_of_self, name_postfix)
290 }
291 }
292 }
293
294 fn get_type(&self) -> &Type {
295 match self {
296 NamedOrUnnamedField::Named(named) => named.get_type(),
297 NamedOrUnnamedField::Unnamed(unnamed) => unnamed.get_type(),
298 }
299 }
300}
301
302impl HasAttributes for NamedOrUnnamedFieldMut<'_> {
303 fn get_attributes(&self) -> &[Attribute] {
304 match self {
305 NamedOrUnnamedFieldMut::Named(named) => named.get_attributes(),
306 NamedOrUnnamedFieldMut::Unnamed(unnamed) => unnamed.get_attributes(),
307 }
308 }
309}
310
311impl Field for NamedOrUnnamedFieldMut<'_> {
312 fn get_type_that_needs_constraint(&self) -> Option<Type> {
313 match self {
314 NamedOrUnnamedFieldMut::Named(named) => named.get_type_that_needs_constraint(),
315 NamedOrUnnamedFieldMut::Unnamed(unnamed) => unnamed.get_type_that_needs_constraint(),
316 }
317 }
318
319 fn get_pattern_with_config(
320 &self,
321 type_of_self: TypeOfSelf,
322 name_postfix: &'static str,
323 ) -> TokenStream {
324 match self {
325 NamedOrUnnamedFieldMut::Named(named) => {
326 named.get_pattern_with_config(type_of_self, name_postfix)
327 }
328 NamedOrUnnamedFieldMut::Unnamed(unnamed) => {
329 unnamed.get_pattern_with_config(type_of_self, name_postfix)
330 }
331 }
332 }
333
334 fn get_type(&self) -> &Type {
335 match self {
336 NamedOrUnnamedFieldMut::Named(named) => named.get_type(),
337 NamedOrUnnamedFieldMut::Unnamed(unnamed) => unnamed.get_type(),
338 }
339 }
340}
341
342impl FieldMut for NamedOrUnnamedFieldMut<'_> {
343 fn get_reference_with_config(
344 &mut self,
345 used_for_trait: bool,
346 name_postfix: &'static str,
347 ) -> Expr {
348 match self {
349 NamedOrUnnamedFieldMut::Named(named) => {
350 named.get_reference_with_config(used_for_trait, name_postfix)
351 }
352 NamedOrUnnamedFieldMut::Unnamed(unnamed) => {
353 unnamed.get_reference_with_config(used_for_trait, name_postfix)
354 }
355 }
356 }
357}
358
359pub struct NamedField {
360 pub name: Ident,
361 pub attrs: Vec<Attribute>,
362 pub ty: Type,
363 idx: usize,
364 is_used: bool,
365 used_for_trait: bool,
366}
367
368impl HasAttributes for NamedField {
369 fn get_attributes(&self) -> &[Attribute] {
370 &self.attrs
371 }
372}
373
374impl Field for NamedField {
375 fn get_pattern_with_config(
376 &self,
377 type_of_self: TypeOfSelf,
378 name_postfix: &'static str,
379 ) -> TokenStream {
380 let Self {
381 name, is_used, idx, ..
382 } = self;
383 if *is_used {
384 let annotations = type_of_self.as_matcher_tokens();
385 let reference_name = format_ident!("_{}{}", idx, name_postfix);
386 quote!(#name: #annotations #reference_name)
387 } else {
388 quote!(#name: _)
389 }
390 }
391
392 fn get_type_that_needs_constraint(&self) -> Option<Type> {
393 self.used_for_trait.then(|| self.ty.clone())
394 }
395
396 fn get_type(&self) -> &Type {
397 &self.ty
398 }
399}
400
401impl FieldMut for NamedField {
402 fn get_reference_with_config(
403 &mut self,
404 used_for_trait: bool,
405 name_postfix: &'static str,
406 ) -> Expr {
407 self.is_used = true;
408 self.used_for_trait |= used_for_trait;
409 let path: Expr = syn::ExprPath {
410 attrs: Vec::new(),
411 qself: None,
412 path: format_ident!("_{}{}", self.idx, name_postfix).into(),
413 }
414 .into();
415 if matches!(self.ty, Type::Reference(..)) {
416 Expr::Unary(ExprUnary {
417 attrs: Vec::default(),
418 op: syn::UnOp::Deref(Token)),
419 expr: Box::new(path),
420 })
421 } else {
422 path
423 }
424 }
425}
426
427pub struct UnnamedField {
428 pub idx: usize,
429 pub attrs: Vec<Attribute>,
430 pub ty: Type,
431 is_used: bool,
432 used_for_trait: bool,
433}
434
435impl HasAttributes for UnnamedField {
436 fn get_attributes(&self) -> &[Attribute] {
437 &self.attrs
438 }
439}
440
441impl Field for UnnamedField {
442 fn get_pattern_with_config(
443 &self,
444 type_of_self: TypeOfSelf,
445 name_postfix: &'static str,
446 ) -> TokenStream {
447 let Self { is_used, idx, .. } = self;
448 if *is_used {
449 let mut ts = type_of_self.as_matcher_tokens();
450 ts.extend(format_ident!("_{}{}", idx, name_postfix).to_token_stream());
451 ts
452 } else {
453 quote!(_)
454 }
455 }
456
457 fn get_type_that_needs_constraint(&self) -> Option<Type> {
458 self.used_for_trait.then(|| self.ty.clone())
459 }
460
461 fn get_type(&self) -> &Type {
462 &self.ty
463 }
464}
465
466impl FieldMut for UnnamedField {
467 fn get_reference_with_config(
468 &mut self,
469 used_for_trait: bool,
470 name_postfix: &'static str,
471 ) -> Expr {
472 self.is_used = true;
473 self.used_for_trait |= used_for_trait;
474 let path: Expr = syn::ExprPath {
475 attrs: Vec::new(),
476 qself: None,
477 path: format_ident!("_{}{}", self.idx, name_postfix).into(),
478 }
479 .into();
480 if matches!(self.ty, Type::Reference(..)) {
481 Expr::Unary(ExprUnary {
482 attrs: Vec::default(),
483 op: syn::UnOp::Deref(Token)),
484 expr: Box::new(path),
485 })
486 } else {
487 path
488 }
489 }
490}