| //! Attribute parsing for fields. |
| |
| use syn::{spanned::Spanned, Attribute, Meta, Result}; |
| |
| use crate::{util::MetaListExt, DeriveWhere, Error, Skip, DERIVE_WHERE}; |
| #[cfg(feature = "zeroize")] |
| use crate::{Trait, ZeroizeFqs}; |
| |
| /// Attributes on field. |
| #[derive(Default)] |
| #[cfg_attr(test, derive(Debug))] |
| pub struct FieldAttr { |
| /// [`Trait`](crate::Trait)s to skip this field for. |
| #[cfg_attr(feature = "zeroize", allow(rustdoc::redundant_explicit_links))] |
| pub skip: Skip, |
| /// Use fully-qualified-syntax for the [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html) implementation on this field. |
| #[cfg(feature = "zeroize")] |
| pub zeroize_fqs: ZeroizeFqs, |
| } |
| |
| impl FieldAttr { |
| /// Create [`FieldAttr`] from [`Attribute`]s. |
| pub fn from_attrs( |
| derive_wheres: &[DeriveWhere], |
| skip_inner: &Skip, |
| attrs: &[Attribute], |
| ) -> Result<Self> { |
| let mut self_ = FieldAttr::default(); |
| |
| for attr in attrs { |
| if attr.path().is_ident(DERIVE_WHERE) { |
| self_.add_meta(derive_wheres, skip_inner, &attr.meta)? |
| } |
| } |
| |
| Ok(self_) |
| } |
| |
| /// Add [`Meta`] to [`FieldAttr`]. |
| fn add_meta( |
| &mut self, |
| derive_wheres: &[DeriveWhere], |
| skip_inner: &Skip, |
| meta: &Meta, |
| ) -> Result<()> { |
| debug_assert!(meta.path().is_ident(DERIVE_WHERE)); |
| |
| if let Meta::List(list) = meta { |
| let nested = list.parse_non_empty_nested_metas()?; |
| |
| for meta in &nested { |
| if meta.path().is_ident(Skip::SKIP) { |
| self.skip |
| .add_attribute(derive_wheres, Some(skip_inner), meta)?; |
| continue; |
| } |
| |
| #[cfg(feature = "zeroize")] |
| { |
| if meta.path().is_ident(Trait::Zeroize.as_str()) { |
| self.zeroize_fqs.add_attribute(meta, derive_wheres)?; |
| continue; |
| } |
| } |
| |
| return Err(Error::option(meta.path().span())); |
| } |
| |
| Ok(()) |
| } else { |
| Err(Error::option_syntax(meta.span())) |
| } |
| } |
| } |