1 | //! Attribute parsing for fields. |
2 | |
3 | use syn::{spanned::Spanned, Attribute, Meta, Result}; |
4 | |
5 | use crate::{util::MetaListExt, DeriveWhere, Error, Skip, DERIVE_WHERE}; |
6 | #[cfg (feature = "zeroize" )] |
7 | use crate::{Trait, TraitImpl, ZeroizeFqs}; |
8 | |
9 | /// Attributes on field. |
10 | #[derive (Default)] |
11 | #[cfg_attr (test, derive(Debug))] |
12 | pub struct FieldAttr { |
13 | /// [`Trait`](crate::Trait)s to skip this field for. |
14 | #[cfg_attr (feature = "zeroize" , allow(rustdoc::redundant_explicit_links))] |
15 | pub skip: Skip, |
16 | /// Use fully-qualified-syntax for the [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html) implementation on this field. |
17 | #[cfg (feature = "zeroize" )] |
18 | pub zeroize_fqs: ZeroizeFqs, |
19 | } |
20 | |
21 | impl FieldAttr { |
22 | /// Create [`FieldAttr`] from [`Attribute`]s. |
23 | pub fn from_attrs( |
24 | derive_wheres: &[DeriveWhere], |
25 | skip_inner: &Skip, |
26 | attrs: &[Attribute], |
27 | ) -> Result<Self> { |
28 | let mut self_ = FieldAttr::default(); |
29 | |
30 | for attr in attrs { |
31 | if attr.path().is_ident(DERIVE_WHERE) { |
32 | self_.add_meta(derive_wheres, skip_inner, &attr.meta)? |
33 | } |
34 | } |
35 | |
36 | Ok(self_) |
37 | } |
38 | |
39 | /// Add [`Meta`] to [`FieldAttr`]. |
40 | fn add_meta( |
41 | &mut self, |
42 | derive_wheres: &[DeriveWhere], |
43 | skip_inner: &Skip, |
44 | meta: &Meta, |
45 | ) -> Result<()> { |
46 | debug_assert!(meta.path().is_ident(DERIVE_WHERE)); |
47 | |
48 | if let Meta::List(list) = meta { |
49 | let nested = list.parse_non_empty_nested_metas()?; |
50 | |
51 | for meta in &nested { |
52 | if meta.path().is_ident(Skip::SKIP) { |
53 | self.skip |
54 | .add_attribute(derive_wheres, Some(skip_inner), meta)?; |
55 | continue; |
56 | } |
57 | |
58 | #[cfg (feature = "zeroize" )] |
59 | { |
60 | if meta.path().is_ident(Trait::Zeroize.as_str()) { |
61 | self.zeroize_fqs.add_attribute(meta, derive_wheres)?; |
62 | continue; |
63 | } |
64 | } |
65 | |
66 | return Err(Error::option(meta.path().span())); |
67 | } |
68 | |
69 | Ok(()) |
70 | } else { |
71 | Err(Error::option_syntax(meta.span())) |
72 | } |
73 | } |
74 | } |
75 | |