// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")]use crate::error::Error;#[cfg(feature = "parsing")]use crate::error::Result;use crate::expr::Expr;use crate::mac::MacroDelimiter;#[cfg(feature = "parsing")]use crate::meta::{self, ParseNestedMeta};#[cfg(feature = "parsing")]use crate::parse::{Parse, ParseStream, Parser};use crate::path::Path;use crate::token;use proc_macro2::TokenStream;#[cfg(feature = "printing")]use std::iter;#[cfg(feature = "printing")]use std::slice; ast_struct! { /// An attribute, like `#[repr(transparent)]`. /// /// <br> /// /// # 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. /// /// ```text /// #[derive(Copy, Clone)] /// ~~~~~~Path /// ^^^^^^^^^^^^^^^^^^^Meta::List /// /// #[path = "sys/windows.rs"] /// ~~~~Path /// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue /// /// #[test] /// ^^^^Meta::Path /// ``` /// /// <br> /// /// # 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. /// /// [`Parse`]: crate::parse::Parse /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse /// [`ParseStream::call`]: crate::parse::ParseBuffer::call /// /// ``` /// 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()?, /// }) /// } /// } /// ``` /// /// <p><br></p> /// /// # 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. /// /// [`parse_args()`]: Attribute::parse_args /// /// <p><br></p> /// /// # 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: /// /// ``` /// # use syn::{ItemMod, parse_quote}; /// 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); /// ``` #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Attribute { pub pound_token: Token![#], pub style: AttrStyle, pub bracket_token: token::Bracket, pub meta: Meta, }} impl Attribute { /// 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"]`. pub fn path(&self) -> &Path { self.meta.path() } /// 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. /// /// ```text /// #[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()?; /// // ... /// } /// # anyhow::Ok(()) /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_args<T: Parse>(&self) -> Result<T> { self.parse_args_with(T::parse) } /// 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()?; /// # anyhow::Ok(()) /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { match &self.meta { Meta::Path(path) => Err(crate::error::new2( path.segments.first().unwrap().ident.span(), path.segments.last().unwrap().ident.span(), format!( "expected attribute arguments in parentheses: {}[{}(...)]", parsing::DisplayAttrStyle(&self.style), parsing::DisplayPath(path), ), )), Meta::NameValue(meta) => Err(Error::new( meta.eq_token.span, format_args!( "expected parentheses: {}[{}(...)]", parsing::DisplayAttrStyle(&self.style), parsing::DisplayPath(&meta.path), ), )), Meta::List(meta) => meta.parse_args_with(parser), } } /// 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*][syntax] section in the Rust reference /// explains the convention in more detail. Not all attributes follow this /// convention, so [`parse_args()`][Self::parse_args] is available if you /// need to parse arbitrarily goofy attribute syntax. /// /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-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")) /// })?; /// } /// } /// # anyhow::Ok(()) /// ``` /// /// # Alternatives /// /// In some cases, for attributes which have nested layers of structured /// content, the following less flexible approach might be more convenient: /// /// ``` /// # use syn::{parse_quote, ItemStruct}; /// # /// # let input: ItemStruct = parse_quote! { /// # #[repr(C, align(4))] /// # pub struct MyStruct(u16, u32); /// # }; /// # /// 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")); /// } /// } /// } /// } /// } /// # Ok(()) /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_nested_meta( &self, logic: impl FnMut(ParseNestedMeta) -> Result<()>, ) -> Result<()> { self.parse_args_with(meta::parser(logic)) } /// Parses zero or more outer attributes from the stream. /// /// # Example /// /// See /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> { let mut attrs = Vec::new(); while input.peek(Token![#]) { attrs.push(input.call(parsing::single_parse_outer)?); } Ok(attrs) } /// Parses zero or more inner attributes from the stream. /// /// # Example /// /// See /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> { let mut attrs = Vec::new(); parsing::parse_inner(input, &mut attrs)?; Ok(attrs) }} ast_enum! { /// Distinguishes between attributes that decorate an item and attributes /// that are contained within an item. /// /// # Outer attributes /// /// - `#[repr(transparent)]` /// - `/// # Example` /// - `/** Please file an issue */` /// /// # Inner attributes /// /// - `#![feature(proc_macro)]` /// - `//! # Example` /// - `/*! Please file an issue */` #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum AttrStyle { Outer, Inner(Token![!]), }} ast_enum! { /// Content of a compile-time structured attribute. /// /// ## Path /// /// A meta path is like the `test` in `#[test]`. /// /// ## List /// /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`. /// /// ## NameValue /// /// A name-value meta is like the `path = "..."` in `#[path = /// "sys/windows.rs"]`. /// /// # Syntax tree enum /// /// This type is a [syntax tree enum]. /// /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum Meta { Path(Path), /// A structured list within an attribute, like `derive(Copy, Clone)`. List(MetaList), /// A name-value pair within an attribute, like `feature = "nightly"`. NameValue(MetaNameValue), }} ast_struct! { /// A structured list within an attribute, like `derive(Copy, Clone)`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct MetaList { pub path: Path, pub delimiter: MacroDelimiter, pub tokens: TokenStream, }} ast_struct! { /// A name-value pair within an attribute, like `feature = "nightly"`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct MetaNameValue { pub path: Path,Lines 1–500 of 838. Load more
// SPDX-License-Identifier: Apache-2.0 OR MIT #[cfg(feature = "parsing")] use crate::error::Error; #[cfg(feature = "parsing")] use crate::error::Result; use crate::expr::Expr; use crate::mac::MacroDelimiter; #[cfg(feature = "parsing")] use crate::meta::{self, ParseNestedMeta}; #[cfg(feature = "parsing")] use crate::parse::{Parse, ParseStream, Parser}; use crate::path::Path; use crate::token; use proc_macro2::TokenStream; #[cfg(feature = "printing")] use std::iter; #[cfg(feature = "printing")] use std::slice; ast_struct! { /// An attribute, like `#[repr(transparent)]`. /// /// <br> /// /// # 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. /// /// ```text /// #[derive(Copy, Clone)] /// ~~~~~~Path /// ^^^^^^^^^^^^^^^^^^^Meta::List /// /// #[path = "sys/windows.rs"] /// ~~~~Path /// ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue /// /// #[test] /// ^^^^Meta::Path /// ``` /// /// <br> /// /// # 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. /// /// [`Parse`]: crate::parse::Parse /// [`ParseStream::parse`]: crate::parse::ParseBuffer::parse /// [`ParseStream::call`]: crate::parse::ParseBuffer::call /// /// ``` /// 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()?, /// }) /// } /// } /// ``` /// /// <p><br></p> /// /// # 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. /// /// [`parse_args()`]: Attribute::parse_args /// /// <p><br></p> /// /// # 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: /// /// ``` /// # use syn::{ItemMod, parse_quote}; /// 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); /// ``` #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct Attribute { pub pound_token: Token![#], pub style: AttrStyle, pub bracket_token: token::Bracket, pub meta: Meta, } } impl Attribute { /// 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"]`. pub fn path(&self) -> &Path { self.meta.path() } /// 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. /// /// ```text /// #[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()?; /// // ... /// } /// # anyhow::Ok(()) /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_args<T: Parse>(&self) -> Result<T> { self.parse_args_with(T::parse) } /// 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()?; /// # anyhow::Ok(()) /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> { match &self.meta { Meta::Path(path) => Err(crate::error::new2( path.segments.first().unwrap().ident.span(), path.segments.last().unwrap().ident.span(), format!( "expected attribute arguments in parentheses: {}[{}(...)]", parsing::DisplayAttrStyle(&self.style), parsing::DisplayPath(path), ), )), Meta::NameValue(meta) => Err(Error::new( meta.eq_token.span, format_args!( "expected parentheses: {}[{}(...)]", parsing::DisplayAttrStyle(&self.style), parsing::DisplayPath(&meta.path), ), )), Meta::List(meta) => meta.parse_args_with(parser), } } /// 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*][syntax] section in the Rust reference /// explains the convention in more detail. Not all attributes follow this /// convention, so [`parse_args()`][Self::parse_args] is available if you /// need to parse arbitrarily goofy attribute syntax. /// /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-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")) /// })?; /// } /// } /// # anyhow::Ok(()) /// ``` /// /// # Alternatives /// /// In some cases, for attributes which have nested layers of structured /// content, the following less flexible approach might be more convenient: /// /// ``` /// # use syn::{parse_quote, ItemStruct}; /// # /// # let input: ItemStruct = parse_quote! { /// # #[repr(C, align(4))] /// # pub struct MyStruct(u16, u32); /// # }; /// # /// 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")); /// } /// } /// } /// } /// } /// # Ok(()) /// ``` #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_nested_meta( &self, logic: impl FnMut(ParseNestedMeta) -> Result<()>, ) -> Result<()> { self.parse_args_with(meta::parser(logic)) } /// Parses zero or more outer attributes from the stream. /// /// # Example /// /// See /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> { let mut attrs = Vec::new(); while input.peek(Token![#]) { attrs.push(input.call(parsing::single_parse_outer)?); } Ok(attrs) } /// Parses zero or more inner attributes from the stream. /// /// # Example /// /// See /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute). #[cfg(feature = "parsing")] #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> { let mut attrs = Vec::new(); parsing::parse_inner(input, &mut attrs)?; Ok(attrs) } } ast_enum! { /// Distinguishes between attributes that decorate an item and attributes /// that are contained within an item. /// /// # Outer attributes /// /// - `#[repr(transparent)]` /// - `/// # Example` /// - `/** Please file an issue */` /// /// # Inner attributes /// /// - `#![feature(proc_macro)]` /// - `//! # Example` /// - `/*! Please file an issue */` #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum AttrStyle { Outer, Inner(Token![!]), } } ast_enum! { /// Content of a compile-time structured attribute. /// /// ## Path /// /// A meta path is like the `test` in `#[test]`. /// /// ## List /// /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`. /// /// ## NameValue /// /// A name-value meta is like the `path = "..."` in `#[path = /// "sys/windows.rs"]`. /// /// # Syntax tree enum /// /// This type is a [syntax tree enum]. /// /// [syntax tree enum]: crate::expr::Expr#syntax-tree-enums #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum Meta { Path(Path), /// A structured list within an attribute, like `derive(Copy, Clone)`. List(MetaList), /// A name-value pair within an attribute, like `feature = "nightly"`. NameValue(MetaNameValue), } } ast_struct! { /// A structured list within an attribute, like `derive(Copy, Clone)`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct MetaList { pub path: Path, pub delimiter: MacroDelimiter, pub tokens: TokenStream, } } ast_struct! { /// A name-value pair within an attribute, like `feature = "nightly"`. #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))] pub struct MetaNameValue { pub path: Path,