pub struct Attribute {
pub pound_token: Pound,
pub style: AttrStyle,
pub bracket_token: Bracket,
pub meta: Meta,
}
Expand description
An attribute, like #[repr(transparent)]
.
Syntax
Rust has six types of attributes.
-
Outer attributes like
#[repr(transparent)]
. These appear outside or in front of the item they describe. -
Inner attributes like
#![feature(proc_macro)]
. These appear inside of the item they describe, usually a module. -
Outer one-line doc comments like
/// Example
. -
Inner one-line doc comments like
//! Please file an issue
. -
Outer documentation blocks
/** Example */
. -
Inner documentation blocks
/*! Please file an issue */
.
The style
field of type AttrStyle
distinguishes whether an attribute
is outer or inner.
Every attribute has a path
that indicates the intended interpretation
of the rest of the attribute’s contents. The path and the optional
additional contents are represented together in the meta
field of the
attribute in three possible varieties:
-
Meta::Path — attributes whose information content conveys just a path, for example the
#[test]
attribute. -
Meta::List — attributes that carry arbitrary tokens after the path, surrounded by a delimiter (parenthesis, bracket, or brace). For example
#[derive(Copy)]
or#[precondition(x < 5)]
. -
Meta::NameValue — attributes with an
=
sign after the path, followed by a Rust expression. For example#[path = "sys/windows.rs"]
.
All doc comments are represented in the NameValue style with a path of
“doc”, as this is how they are processed by the compiler and by
macro_rules!
macros.
#[derive(Copy, Clone)]
~~~~~~Path
^^^^^^^^^^^^^^^^^^^Meta::List
#[path = "sys/windows.rs"]
~~~~Path
^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue
#[test]
^^^^Meta::Path
Parsing from tokens to Attribute
This type does not implement the Parse
trait and thus cannot be
parsed directly by ParseStream::parse
. Instead use
ParseStream::call
with one of the two parser functions
Attribute::parse_outer
or Attribute::parse_inner
depending on
which you intend to parse.
use syn::{Attribute, Ident, Result, Token};
use syn::parse::{Parse, ParseStream};
// Parses a unit struct with attributes.
//
// #[path = "s.tmpl"]
// struct S;
struct UnitStruct {
attrs: Vec<Attribute>,
struct_token: Token![struct],
name: Ident,
semi_token: Token![;],
}
impl Parse for UnitStruct {
fn parse(input: ParseStream) -> Result<Self> {
Ok(UnitStruct {
attrs: input.call(Attribute::parse_outer)?,
struct_token: input.parse()?,
name: input.parse()?,
semi_token: input.parse()?,
})
}
}
Parsing from Attribute to structured arguments
The grammar of attributes in Rust is very flexible, which makes the
syntax tree not that useful on its own. In particular, arguments of the
Meta::List
variety of attribute are held in an arbitrary tokens: TokenStream
. Macros are expected to check the path
of the attribute,
decide whether they recognize it, and then parse the remaining tokens
according to whatever grammar they wish to require for that kind of
attribute. Use parse_args()
to parse those tokens into the expected
data structure.
Doc comments
The compiler transforms doc comments, such as /// comment
and /*! comment */
, into attributes before macros are expanded. Each comment is
expanded into an attribute of the form #[doc = r"comment"]
.
As an example, the following mod
items are expanded identically:
let doc: ItemMod = parse_quote! {
/// Single line doc comments
/// We write so many!
/**
* Multi-line comments...
* May span many lines
*/
mod example {
//! Of course, they can be inner too
/*! And fit in a single line */
}
};
let attr: ItemMod = parse_quote! {
#[doc = r" Single line doc comments"]
#[doc = r" We write so many!"]
#[doc = r"
* Multi-line comments...
* May span many lines
"]
mod example {
#![doc = r" Of course, they can be inner too"]
#![doc = r" And fit in a single line "]
}
};
assert_eq!(doc, attr);
Fields§
§pound_token: Pound
§style: AttrStyle
§bracket_token: Bracket
§meta: Meta
Implementations§
source§impl Attribute
impl Attribute
sourcepub fn path(&self) -> &Path
pub fn path(&self) -> &Path
Returns the path that identifies the interpretation of this attribute.
For example this would return the test
in #[test]
, the derive
in
#[derive(Copy)]
, and the path
in #[path = "sys/windows.rs"]
.
sourcepub fn parse_args<T: Parse>(&self) -> Result<T>
pub fn parse_args<T: Parse>(&self) -> Result<T>
Parse the arguments to the attribute as a syntax tree.
This is similar to pulling out the TokenStream
from Meta::List
and
doing syn::parse2::<T>(meta_list.tokens)
, except that using
parse_args
the error message has a more useful span when tokens
is
empty.
The surrounding delimiters are not included in the input to the parser.
#[my_attr(value < 5)]
^^^^^^^^^ what gets parsed
Example
use syn::{parse_quote, Attribute, Expr};
let attr: Attribute = parse_quote! {
#[precondition(value < 5)]
};
if attr.path().is_ident("precondition") {
let precondition: Expr = attr.parse_args()?;
// ...
}
sourcepub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output>
pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output>
Parse the arguments to the attribute using the given parser.
Example
use syn::{parse_quote, Attribute};
let attr: Attribute = parse_quote! {
#[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }]
};
let bwom = attr.parse_args_with(Attribute::parse_outer)?;
// Attribute does not have a Parse impl, so we couldn't directly do:
// let bwom: Attribute = attr.parse_args()?;
sourcepub fn parse_nested_meta(
&self,
logic: impl FnMut(ParseNestedMeta<'_>) -> Result<()>
) -> Result<()>
pub fn parse_nested_meta(
&self,
logic: impl FnMut(ParseNestedMeta<'_>) -> Result<()>
) -> Result<()>
Parse the arguments to the attribute, expecting it to follow the conventional structure used by most of Rust’s built-in attributes.
The Meta Item Attribute Syntax section in the Rust reference
explains the convention in more detail. Not all attributes follow this
convention, so parse_args()
is available if you
need to parse arbitrarily goofy attribute syntax.
Example
We’ll parse a struct, and then parse some of Rust’s #[repr]
attribute
syntax.
use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt};
let input: ItemStruct = parse_quote! {
#[repr(C, align(4))]
pub struct MyStruct(u16, u32);
};
let mut repr_c = false;
let mut repr_transparent = false;
let mut repr_align = None::<usize>;
let mut repr_packed = None::<usize>;
for attr in &input.attrs {
if attr.path().is_ident("repr") {
attr.parse_nested_meta(|meta| {
// #[repr(C)]
if meta.path.is_ident("C") {
repr_c = true;
return Ok(());
}
// #[repr(transparent)]
if meta.path.is_ident("transparent") {
repr_transparent = true;
return Ok(());
}
// #[repr(align(N))]
if meta.path.is_ident("align") {
let content;
parenthesized!(content in meta.input);
let lit: LitInt = content.parse()?;
let n: usize = lit.base10_parse()?;
repr_align = Some(n);
return Ok(());
}
// #[repr(packed)] or #[repr(packed(N))], omitted N means 1
if meta.path.is_ident("packed") {
if meta.input.peek(token::Paren) {
let content;
parenthesized!(content in meta.input);
let lit: LitInt = content.parse()?;
let n: usize = lit.base10_parse()?;
repr_packed = Some(n);
} else {
repr_packed = Some(1);
}
return Ok(());
}
Err(meta.error("unrecognized repr"))
})?;
}
}
Alternatives
In some cases, for attributes which have nested layers of structured content, the following less flexible approach might be more convenient:
use syn::punctuated::Punctuated;
use syn::{parenthesized, token, Error, LitInt, Meta, Token};
let mut repr_c = false;
let mut repr_transparent = false;
let mut repr_align = None::<usize>;
let mut repr_packed = None::<usize>;
for attr in &input.attrs {
if attr.path().is_ident("repr") {
let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
for meta in nested {
match meta {
// #[repr(C)]
Meta::Path(path) if path.is_ident("C") => {
repr_c = true;
}
// #[repr(align(N))]
Meta::List(meta) if meta.path.is_ident("align") => {
let lit: LitInt = meta.parse_args()?;
let n: usize = lit.base10_parse()?;
repr_align = Some(n);
}
/* ... */
_ => {
return Err(Error::new_spanned(meta, "unrecognized repr"));
}
}
}
}
}
sourcepub fn parse_outer(input: ParseStream<'_>) -> Result<Vec<Self>>
pub fn parse_outer(input: ParseStream<'_>) -> Result<Vec<Self>>
sourcepub fn parse_inner(input: ParseStream<'_>) -> Result<Vec<Self>>
pub fn parse_inner(input: ParseStream<'_>) -> Result<Vec<Self>>
Trait Implementations§
source§impl ToTokens for Attribute
impl ToTokens for Attribute
source§fn to_tokens(&self, tokens: &mut TokenStream)
fn to_tokens(&self, tokens: &mut TokenStream)
source§fn to_token_stream(&self) -> TokenStream
fn to_token_stream(&self) -> TokenStream
source§fn into_token_stream(self) -> TokenStreamwhere
Self: Sized,
fn into_token_stream(self) -> TokenStreamwhere
Self: Sized,
Auto Trait Implementations§
impl RefUnwindSafe for Attribute
impl !Send for Attribute
impl !Sync for Attribute
impl Unpin for Attribute
impl UnwindSafe for Attribute
Blanket Implementations§
source§impl<T> Spanned for Twhere
T: Spanned + ?Sized,
impl<T> Spanned for Twhere
T: Spanned + ?Sized,
source§fn span(&self) -> Span
fn span(&self) -> Span
Span
covering the complete contents of this syntax tree
node, or Span::call_site()
if this node is empty.