1 | //! Storage for items or variants with data. |
2 | |
3 | use syn::{ |
4 | token::{Brace, Paren}, |
5 | FieldPat, FieldsNamed, FieldsUnnamed, Ident, Pat, PatIdent, PatStruct, PatTupleStruct, Path, |
6 | Result, Token, |
7 | }; |
8 | |
9 | use crate::{DeriveWhere, Field, Skip, Trait}; |
10 | |
11 | /// Struct, union, struct variant or tuple variant fields. |
12 | #[cfg_attr (test, derive(Debug))] |
13 | pub struct Fields<'a> { |
14 | /// [Pattern](Pat) to use in a match arm to destructure `self`. |
15 | pub self_pattern: Pat, |
16 | /// [Pattern](Pat) to use in a match arm to destructure `other`. |
17 | pub other_pattern: Pat, |
18 | /// [`Field`]s of this struct, union or variant. |
19 | pub fields: Vec<Field<'a>>, |
20 | } |
21 | |
22 | impl<'a> Fields<'a> { |
23 | /// Create [`Fields`]s from [`FieldsNamed`]. |
24 | pub fn from_named( |
25 | derive_wheres: &[DeriveWhere], |
26 | skip_inner: &Skip, |
27 | path: Path, |
28 | fields: &'a FieldsNamed, |
29 | ) -> Result<Self> { |
30 | let fields = Field::from_named(derive_wheres, skip_inner, fields)?; |
31 | |
32 | let self_pattern = Self::struct_pattern(path.clone(), &fields, |field| &field.self_ident); |
33 | let other_pattern = Self::struct_pattern(path, &fields, |field| &field.other_ident); |
34 | |
35 | Ok(Self { |
36 | self_pattern, |
37 | other_pattern, |
38 | fields, |
39 | }) |
40 | } |
41 | |
42 | /// Create [`Fields`]s from [`FieldsUnnamed`]. |
43 | pub fn from_unnamed( |
44 | derive_wheres: &[DeriveWhere], |
45 | skip_inner: &Skip, |
46 | path: Path, |
47 | fields: &'a FieldsUnnamed, |
48 | ) -> Result<Self> { |
49 | let fields = Field::from_unnamed(derive_wheres, skip_inner, fields)?; |
50 | |
51 | let self_pattern = Self::tuple_pattern(path.clone(), &fields, |field| &field.self_ident); |
52 | let other_pattern = Self::tuple_pattern(path, &fields, |field| &field.other_ident); |
53 | |
54 | Ok(Self { |
55 | self_pattern, |
56 | other_pattern, |
57 | fields, |
58 | }) |
59 | } |
60 | |
61 | /// Destructuring pattern in a match arm for this item or variant. |
62 | fn struct_pattern( |
63 | path: Path, |
64 | fields: &[Field], |
65 | field_ident: impl for<'b> Fn(&'b Field) -> &'b Ident, |
66 | ) -> Pat { |
67 | Pat::Struct(PatStruct { |
68 | attrs: Vec::new(), |
69 | qself: None, |
70 | path, |
71 | brace_token: Brace::default(), |
72 | fields: fields |
73 | .iter() |
74 | .map(|field| FieldPat { |
75 | attrs: Vec::new(), |
76 | member: field.to_member(), |
77 | colon_token: Some(<Token![:]>::default()), |
78 | pat: Box::new(Pat::Ident(PatIdent { |
79 | attrs: Vec::new(), |
80 | by_ref: Some(<Token![ref]>::default()), |
81 | mutability: None, |
82 | ident: field_ident(field).clone(), |
83 | subpat: None, |
84 | })), |
85 | }) |
86 | .collect(), |
87 | rest: None, |
88 | }) |
89 | } |
90 | |
91 | /// Destructuring pattern in a match arm for this item or variant. |
92 | fn tuple_pattern( |
93 | path: Path, |
94 | fields: &[Field], |
95 | field_ident: impl for<'b> Fn(&'b Field) -> &'b Ident, |
96 | ) -> Pat { |
97 | Pat::TupleStruct(PatTupleStruct { |
98 | attrs: Vec::new(), |
99 | qself: None, |
100 | path, |
101 | paren_token: Paren::default(), |
102 | elems: fields |
103 | .iter() |
104 | .map(|field| { |
105 | Pat::Ident(PatIdent { |
106 | attrs: Vec::new(), |
107 | by_ref: Some(<Token![ref]>::default()), |
108 | mutability: None, |
109 | ident: field_ident(field).clone(), |
110 | subpat: None, |
111 | }) |
112 | }) |
113 | .collect(), |
114 | }) |
115 | } |
116 | |
117 | /// Returns a [Pattern](Pat) to use in a match arm to destructure `self` as |
118 | /// mutable. |
119 | #[cfg (feature = "zeroize" )] |
120 | pub fn self_pattern_mut(&self) -> Pat { |
121 | let mut pattern = self.self_pattern.clone(); |
122 | |
123 | match &mut pattern { |
124 | Pat::Struct(pattern) => { |
125 | for field in &mut pattern.fields { |
126 | if let Pat::Ident(pattern) = &mut *field.pat { |
127 | pattern.mutability = Some(<Token![mut]>::default()); |
128 | } else { |
129 | unreachable!("unexpected pattern" ) |
130 | } |
131 | } |
132 | } |
133 | Pat::TupleStruct(pattern) => { |
134 | for field in &mut pattern.elems { |
135 | if let Pat::Ident(pattern) = &mut *field { |
136 | pattern.mutability = Some(<Token![mut]>::default()); |
137 | } else { |
138 | unreachable!("unexpected pattern" ) |
139 | } |
140 | } |
141 | } |
142 | _ => unreachable!("unexpected pattern" ), |
143 | } |
144 | |
145 | pattern |
146 | } |
147 | |
148 | /// Returns `true` if any field is skipped with that [`Trait`]. |
149 | pub fn any_skip_trait(&self, trait_: Trait) -> bool { |
150 | self.fields.iter().any(|field| field.skip(trait_)) |
151 | } |
152 | |
153 | /// Returns `true` if all fields are skipped with that [`Trait`]. |
154 | pub fn skip(&self, trait_: Trait) -> bool { |
155 | self.fields.iter().all(|field| field.skip(trait_)) |
156 | } |
157 | } |
158 | |