| 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 | |