diff options
Diffstat (limited to 'src/options/forward_attrs.rs')
-rw-r--r-- | src/options/forward_attrs.rs | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/options/forward_attrs.rs b/src/options/forward_attrs.rs new file mode 100644 index 0000000..abe2d85 --- /dev/null +++ b/src/options/forward_attrs.rs @@ -0,0 +1,73 @@ +use proc_macro2::Ident; +use syn::Path; + +use crate::ast::NestedMeta; +use crate::util::PathList; +use crate::{Error, FromField, FromMeta, Result}; + +use super::ParseAttribute; + +/// The `attrs` magic field and attributes that influence its behavior. +#[derive(Debug, Clone)] +pub struct AttrsField { + /// The ident of the field that will receive the forwarded attributes. + pub ident: Ident, + /// Path of the function that will be called to convert the `Vec` of + /// forwarded attributes into the type expected by the field in `ident`. + pub with: Option<Path>, +} + +impl FromField for AttrsField { + fn from_field(field: &syn::Field) -> crate::Result<Self> { + let result = Self { + ident: field.ident.clone().ok_or_else(|| { + Error::custom("attributes receiver must be named field").with_span(field) + })?, + with: None, + }; + + result.parse_attributes(&field.attrs) + } +} + +impl ParseAttribute for AttrsField { + fn parse_nested(&mut self, mi: &syn::Meta) -> crate::Result<()> { + if mi.path().is_ident("with") { + if self.with.is_some() { + return Err(Error::duplicate_field_path(mi.path()).with_span(mi)); + } + + self.with = FromMeta::from_meta(mi)?; + Ok(()) + } else { + Err(Error::unknown_field_path_with_alts(mi.path(), &["with"]).with_span(mi)) + } + } +} + +/// A rule about which attributes to forward to the generated struct. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ForwardAttrsFilter { + All, + Only(PathList), +} + +impl ForwardAttrsFilter { + /// Returns `true` if this will not forward any attributes. + pub fn is_empty(&self) -> bool { + match *self { + ForwardAttrsFilter::All => false, + ForwardAttrsFilter::Only(ref list) => list.is_empty(), + } + } +} + +impl FromMeta for ForwardAttrsFilter { + fn from_word() -> Result<Self> { + Ok(ForwardAttrsFilter::All) + } + + fn from_list(nested: &[NestedMeta]) -> Result<Self> { + Ok(ForwardAttrsFilter::Only(PathList::from_list(nested)?)) + } +} |