• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use super::*;
2 use proc_macro2::TokenStream;
3 use std::iter;
4 use std::slice;
5 
6 #[cfg(feature = "parsing")]
7 use crate::meta::{self, ParseNestedMeta};
8 #[cfg(feature = "parsing")]
9 use crate::parse::{Parse, ParseStream, Parser, Result};
10 
11 ast_struct! {
12     /// An attribute, like `#[repr(transparent)]`.
13     ///
14     /// <br>
15     ///
16     /// # Syntax
17     ///
18     /// Rust has six types of attributes.
19     ///
20     /// - Outer attributes like `#[repr(transparent)]`. These appear outside or
21     ///   in front of the item they describe.
22     ///
23     /// - Inner attributes like `#![feature(proc_macro)]`. These appear inside
24     ///   of the item they describe, usually a module.
25     ///
26     /// - Outer one-line doc comments like `/// Example`.
27     ///
28     /// - Inner one-line doc comments like `//! Please file an issue`.
29     ///
30     /// - Outer documentation blocks `/** Example */`.
31     ///
32     /// - Inner documentation blocks `/*! Please file an issue */`.
33     ///
34     /// The `style` field of type `AttrStyle` distinguishes whether an attribute
35     /// is outer or inner.
36     ///
37     /// Every attribute has a `path` that indicates the intended interpretation
38     /// of the rest of the attribute's contents. The path and the optional
39     /// additional contents are represented together in the `meta` field of the
40     /// attribute in three possible varieties:
41     ///
42     /// - Meta::Path &mdash; attributes whose information content conveys just a
43     ///   path, for example the `#[test]` attribute.
44     ///
45     /// - Meta::List &mdash; attributes that carry arbitrary tokens after the
46     ///   path, surrounded by a delimiter (parenthesis, bracket, or brace). For
47     ///   example `#[derive(Copy)]` or `#[precondition(x < 5)]`.
48     ///
49     /// - Meta::NameValue &mdash; attributes with an `=` sign after the path,
50     ///   followed by a Rust expression. For example `#[path =
51     ///   "sys/windows.rs"]`.
52     ///
53     /// All doc comments are represented in the NameValue style with a path of
54     /// "doc", as this is how they are processed by the compiler and by
55     /// `macro_rules!` macros.
56     ///
57     /// ```text
58     /// #[derive(Copy, Clone)]
59     ///   ~~~~~~Path
60     ///   ^^^^^^^^^^^^^^^^^^^Meta::List
61     ///
62     /// #[path = "sys/windows.rs"]
63     ///   ~~~~Path
64     ///   ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue
65     ///
66     /// #[test]
67     ///   ^^^^Meta::Path
68     /// ```
69     ///
70     /// <br>
71     ///
72     /// # Parsing from tokens to Attribute
73     ///
74     /// This type does not implement the [`Parse`] trait and thus cannot be
75     /// parsed directly by [`ParseStream::parse`]. Instead use
76     /// [`ParseStream::call`] with one of the two parser functions
77     /// [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on
78     /// which you intend to parse.
79     ///
80     /// [`Parse`]: parse::Parse
81     /// [`ParseStream::parse`]: parse::ParseBuffer::parse
82     /// [`ParseStream::call`]: parse::ParseBuffer::call
83     ///
84     /// ```
85     /// use syn::{Attribute, Ident, Result, Token};
86     /// use syn::parse::{Parse, ParseStream};
87     ///
88     /// // Parses a unit struct with attributes.
89     /// //
90     /// //     #[path = "s.tmpl"]
91     /// //     struct S;
92     /// struct UnitStruct {
93     ///     attrs: Vec<Attribute>,
94     ///     struct_token: Token![struct],
95     ///     name: Ident,
96     ///     semi_token: Token![;],
97     /// }
98     ///
99     /// impl Parse for UnitStruct {
100     ///     fn parse(input: ParseStream) -> Result<Self> {
101     ///         Ok(UnitStruct {
102     ///             attrs: input.call(Attribute::parse_outer)?,
103     ///             struct_token: input.parse()?,
104     ///             name: input.parse()?,
105     ///             semi_token: input.parse()?,
106     ///         })
107     ///     }
108     /// }
109     /// ```
110     ///
111     /// <p><br></p>
112     ///
113     /// # Parsing from Attribute to structured arguments
114     ///
115     /// The grammar of attributes in Rust is very flexible, which makes the
116     /// syntax tree not that useful on its own. In particular, arguments of the
117     /// `Meta::List` variety of attribute are held in an arbitrary `tokens:
118     /// TokenStream`. Macros are expected to check the `path` of the attribute,
119     /// decide whether they recognize it, and then parse the remaining tokens
120     /// according to whatever grammar they wish to require for that kind of
121     /// attribute. Use [`parse_args()`] to parse those tokens into the expected
122     /// data structure.
123     ///
124     /// [`parse_args()`]: Attribute::parse_args
125     ///
126     /// <p><br></p>
127     ///
128     /// # Doc comments
129     ///
130     /// The compiler transforms doc comments, such as `/// comment` and `/*!
131     /// comment */`, into attributes before macros are expanded. Each comment is
132     /// expanded into an attribute of the form `#[doc = r"comment"]`.
133     ///
134     /// As an example, the following `mod` items are expanded identically:
135     ///
136     /// ```
137     /// # use syn::{ItemMod, parse_quote};
138     /// let doc: ItemMod = parse_quote! {
139     ///     /// Single line doc comments
140     ///     /// We write so many!
141     ///     /**
142     ///      * Multi-line comments...
143     ///      * May span many lines
144     ///      */
145     ///     mod example {
146     ///         //! Of course, they can be inner too
147     ///         /*! And fit in a single line */
148     ///     }
149     /// };
150     /// let attr: ItemMod = parse_quote! {
151     ///     #[doc = r" Single line doc comments"]
152     ///     #[doc = r" We write so many!"]
153     ///     #[doc = r"
154     ///      * Multi-line comments...
155     ///      * May span many lines
156     ///      "]
157     ///     mod example {
158     ///         #![doc = r" Of course, they can be inner too"]
159     ///         #![doc = r" And fit in a single line "]
160     ///     }
161     /// };
162     /// assert_eq!(doc, attr);
163     /// ```
164     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
165     pub struct Attribute {
166         pub pound_token: Token![#],
167         pub style: AttrStyle,
168         pub bracket_token: token::Bracket,
169         pub meta: Meta,
170     }
171 }
172 
173 impl Attribute {
174     /// Returns the path that identifies the interpretation of this attribute.
175     ///
176     /// For example this would return the `test` in `#[test]`, the `derive` in
177     /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
path(&self) -> &Path178     pub fn path(&self) -> &Path {
179         self.meta.path()
180     }
181 
182     /// Parse the arguments to the attribute as a syntax tree.
183     ///
184     /// This is similar to pulling out the `TokenStream` from `Meta::List` and
185     /// doing `syn::parse2::<T>(meta_list.tokens)`, except that using
186     /// `parse_args` the error message has a more useful span when `tokens` is
187     /// empty.
188     ///
189     /// The surrounding delimiters are *not* included in the input to the
190     /// parser.
191     ///
192     /// ```text
193     /// #[my_attr(value < 5)]
194     ///           ^^^^^^^^^ what gets parsed
195     /// ```
196     ///
197     /// # Example
198     ///
199     /// ```
200     /// use syn::{parse_quote, Attribute, Expr};
201     ///
202     /// let attr: Attribute = parse_quote! {
203     ///     #[precondition(value < 5)]
204     /// };
205     ///
206     /// if attr.path().is_ident("precondition") {
207     ///     let precondition: Expr = attr.parse_args()?;
208     ///     // ...
209     /// }
210     /// # anyhow::Ok(())
211     /// ```
212     #[cfg(feature = "parsing")]
213     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_args<T: Parse>(&self) -> Result<T>214     pub fn parse_args<T: Parse>(&self) -> Result<T> {
215         self.parse_args_with(T::parse)
216     }
217 
218     /// Parse the arguments to the attribute using the given parser.
219     ///
220     /// # Example
221     ///
222     /// ```
223     /// use syn::{parse_quote, Attribute};
224     ///
225     /// let attr: Attribute = parse_quote! {
226     ///     #[inception { #[brrrrrrraaaaawwwwrwrrrmrmrmmrmrmmmmm] }]
227     /// };
228     ///
229     /// let bwom = attr.parse_args_with(Attribute::parse_outer)?;
230     ///
231     /// // Attribute does not have a Parse impl, so we couldn't directly do:
232     /// // let bwom: Attribute = attr.parse_args()?;
233     /// # anyhow::Ok(())
234     /// ```
235     #[cfg(feature = "parsing")]
236     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output>237     pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
238         match &self.meta {
239             Meta::Path(path) => Err(crate::error::new2(
240                 path.segments.first().unwrap().ident.span(),
241                 path.segments.last().unwrap().ident.span(),
242                 format!(
243                     "expected attribute arguments in parentheses: {}[{}(...)]",
244                     parsing::DisplayAttrStyle(&self.style),
245                     parsing::DisplayPath(path),
246                 ),
247             )),
248             Meta::NameValue(meta) => Err(Error::new(
249                 meta.eq_token.span,
250                 format_args!(
251                     "expected parentheses: {}[{}(...)]",
252                     parsing::DisplayAttrStyle(&self.style),
253                     parsing::DisplayPath(&meta.path),
254                 ),
255             )),
256             Meta::List(meta) => meta.parse_args_with(parser),
257         }
258     }
259 
260     /// Parse the arguments to the attribute, expecting it to follow the
261     /// conventional structure used by most of Rust's built-in attributes.
262     ///
263     /// The [*Meta Item Attribute Syntax*][syntax] section in the Rust reference
264     /// explains the convention in more detail. Not all attributes follow this
265     /// convention, so [`parse_args()`][Self::parse_args] is available if you
266     /// need to parse arbitrarily goofy attribute syntax.
267     ///
268     /// [syntax]: https://doc.rust-lang.org/reference/attributes.html#meta-item-attribute-syntax
269     ///
270     /// # Example
271     ///
272     /// We'll parse a struct, and then parse some of Rust's `#[repr]` attribute
273     /// syntax.
274     ///
275     /// ```
276     /// use syn::{parenthesized, parse_quote, token, ItemStruct, LitInt};
277     ///
278     /// let input: ItemStruct = parse_quote! {
279     ///     #[repr(C, align(4))]
280     ///     pub struct MyStruct(u16, u32);
281     /// };
282     ///
283     /// let mut repr_c = false;
284     /// let mut repr_transparent = false;
285     /// let mut repr_align = None::<usize>;
286     /// let mut repr_packed = None::<usize>;
287     /// for attr in &input.attrs {
288     ///     if attr.path().is_ident("repr") {
289     ///         attr.parse_nested_meta(|meta| {
290     ///             // #[repr(C)]
291     ///             if meta.path.is_ident("C") {
292     ///                 repr_c = true;
293     ///                 return Ok(());
294     ///             }
295     ///
296     ///             // #[repr(transparent)]
297     ///             if meta.path.is_ident("transparent") {
298     ///                 repr_transparent = true;
299     ///                 return Ok(());
300     ///             }
301     ///
302     ///             // #[repr(align(N))]
303     ///             if meta.path.is_ident("align") {
304     ///                 let content;
305     ///                 parenthesized!(content in meta.input);
306     ///                 let lit: LitInt = content.parse()?;
307     ///                 let n: usize = lit.base10_parse()?;
308     ///                 repr_align = Some(n);
309     ///                 return Ok(());
310     ///             }
311     ///
312     ///             // #[repr(packed)] or #[repr(packed(N))], omitted N means 1
313     ///             if meta.path.is_ident("packed") {
314     ///                 if meta.input.peek(token::Paren) {
315     ///                     let content;
316     ///                     parenthesized!(content in meta.input);
317     ///                     let lit: LitInt = content.parse()?;
318     ///                     let n: usize = lit.base10_parse()?;
319     ///                     repr_packed = Some(n);
320     ///                 } else {
321     ///                     repr_packed = Some(1);
322     ///                 }
323     ///                 return Ok(());
324     ///             }
325     ///
326     ///             Err(meta.error("unrecognized repr"))
327     ///         })?;
328     ///     }
329     /// }
330     /// # anyhow::Ok(())
331     /// ```
332     ///
333     /// # Alternatives
334     ///
335     /// In some cases, for attributes which have nested layers of structured
336     /// content, the following less flexible approach might be more convenient:
337     ///
338     /// ```
339     /// # use syn::{parse_quote, ItemStruct};
340     /// #
341     /// # let input: ItemStruct = parse_quote! {
342     /// #     #[repr(C, align(4))]
343     /// #     pub struct MyStruct(u16, u32);
344     /// # };
345     /// #
346     /// use syn::punctuated::Punctuated;
347     /// use syn::{parenthesized, token, Error, LitInt, Meta, Token};
348     ///
349     /// let mut repr_c = false;
350     /// let mut repr_transparent = false;
351     /// let mut repr_align = None::<usize>;
352     /// let mut repr_packed = None::<usize>;
353     /// for attr in &input.attrs {
354     ///     if attr.path().is_ident("repr") {
355     ///         let nested = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?;
356     ///         for meta in nested {
357     ///             match meta {
358     ///                 // #[repr(C)]
359     ///                 Meta::Path(path) if path.is_ident("C") => {
360     ///                     repr_c = true;
361     ///                 }
362     ///
363     ///                 // #[repr(align(N))]
364     ///                 Meta::List(meta) if meta.path.is_ident("align") => {
365     ///                     let lit: LitInt = meta.parse_args()?;
366     ///                     let n: usize = lit.base10_parse()?;
367     ///                     repr_align = Some(n);
368     ///                 }
369     ///
370     ///                 /* ... */
371     ///
372     ///                 _ => {
373     ///                     return Err(Error::new_spanned(meta, "unrecognized repr"));
374     ///                 }
375     ///             }
376     ///         }
377     ///     }
378     /// }
379     /// # Ok(())
380     /// ```
381     #[cfg(feature = "parsing")]
382     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_nested_meta( &self, logic: impl FnMut(ParseNestedMeta) -> Result<()>, ) -> Result<()>383     pub fn parse_nested_meta(
384         &self,
385         logic: impl FnMut(ParseNestedMeta) -> Result<()>,
386     ) -> Result<()> {
387         self.parse_args_with(meta::parser(logic))
388     }
389 
390     /// Parses zero or more outer attributes from the stream.
391     ///
392     /// # Example
393     ///
394     /// See
395     /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
396     #[cfg(feature = "parsing")]
397     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_outer(input: ParseStream) -> Result<Vec<Self>>398     pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
399         let mut attrs = Vec::new();
400         while input.peek(Token![#]) {
401             attrs.push(input.call(parsing::single_parse_outer)?);
402         }
403         Ok(attrs)
404     }
405 
406     /// Parses zero or more inner attributes from the stream.
407     ///
408     /// # Example
409     ///
410     /// See
411     /// [*Parsing from tokens to Attribute*](#parsing-from-tokens-to-attribute).
412     #[cfg(feature = "parsing")]
413     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_inner(input: ParseStream) -> Result<Vec<Self>>414     pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
415         let mut attrs = Vec::new();
416         parsing::parse_inner(input, &mut attrs)?;
417         Ok(attrs)
418     }
419 }
420 
421 ast_enum! {
422     /// Distinguishes between attributes that decorate an item and attributes
423     /// that are contained within an item.
424     ///
425     /// # Outer attributes
426     ///
427     /// - `#[repr(transparent)]`
428     /// - `/// # Example`
429     /// - `/** Please file an issue */`
430     ///
431     /// # Inner attributes
432     ///
433     /// - `#![feature(proc_macro)]`
434     /// - `//! # Example`
435     /// - `/*! Please file an issue */`
436     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
437     pub enum AttrStyle {
438         Outer,
439         Inner(Token![!]),
440     }
441 }
442 
443 ast_enum_of_structs! {
444     /// Content of a compile-time structured attribute.
445     ///
446     /// ## Path
447     ///
448     /// A meta path is like the `test` in `#[test]`.
449     ///
450     /// ## List
451     ///
452     /// A meta list is like the `derive(Copy)` in `#[derive(Copy)]`.
453     ///
454     /// ## NameValue
455     ///
456     /// A name-value meta is like the `path = "..."` in `#[path =
457     /// "sys/windows.rs"]`.
458     ///
459     /// # Syntax tree enum
460     ///
461     /// This type is a [syntax tree enum].
462     ///
463     /// [syntax tree enum]: Expr#syntax-tree-enums
464     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
465     pub enum Meta {
466         Path(Path),
467 
468         /// A structured list within an attribute, like `derive(Copy, Clone)`.
469         List(MetaList),
470 
471         /// A name-value pair within an attribute, like `feature = "nightly"`.
472         NameValue(MetaNameValue),
473     }
474 }
475 
476 ast_struct! {
477     /// A structured list within an attribute, like `derive(Copy, Clone)`.
478     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
479     pub struct MetaList {
480         pub path: Path,
481         pub delimiter: MacroDelimiter,
482         pub tokens: TokenStream,
483     }
484 }
485 
486 ast_struct! {
487     /// A name-value pair within an attribute, like `feature = "nightly"`.
488     #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))]
489     pub struct MetaNameValue {
490         pub path: Path,
491         pub eq_token: Token![=],
492         pub value: Expr,
493     }
494 }
495 
496 impl Meta {
497     /// Returns the path that begins this structured meta item.
498     ///
499     /// For example this would return the `test` in `#[test]`, the `derive` in
500     /// `#[derive(Copy)]`, and the `path` in `#[path = "sys/windows.rs"]`.
path(&self) -> &Path501     pub fn path(&self) -> &Path {
502         match self {
503             Meta::Path(path) => path,
504             Meta::List(meta) => &meta.path,
505             Meta::NameValue(meta) => &meta.path,
506         }
507     }
508 
509     /// Error if this is a `Meta::List` or `Meta::NameValue`.
510     #[cfg(feature = "parsing")]
511     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
require_path_only(&self) -> Result<&Path>512     pub fn require_path_only(&self) -> Result<&Path> {
513         let error_span = match self {
514             Meta::Path(path) => return Ok(path),
515             Meta::List(meta) => meta.delimiter.span().open(),
516             Meta::NameValue(meta) => meta.eq_token.span,
517         };
518         Err(Error::new(error_span, "unexpected token in attribute"))
519     }
520 
521     /// Error if this is a `Meta::Path` or `Meta::NameValue`.
522     #[cfg(feature = "parsing")]
523     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
require_list(&self) -> Result<&MetaList>524     pub fn require_list(&self) -> Result<&MetaList> {
525         match self {
526             Meta::List(meta) => Ok(meta),
527             Meta::Path(path) => Err(crate::error::new2(
528                 path.segments.first().unwrap().ident.span(),
529                 path.segments.last().unwrap().ident.span(),
530                 format!(
531                     "expected attribute arguments in parentheses: `{}(...)`",
532                     parsing::DisplayPath(path),
533                 ),
534             )),
535             Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")),
536         }
537     }
538 
539     /// Error if this is a `Meta::Path` or `Meta::List`.
540     #[cfg(feature = "parsing")]
541     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
require_name_value(&self) -> Result<&MetaNameValue>542     pub fn require_name_value(&self) -> Result<&MetaNameValue> {
543         match self {
544             Meta::NameValue(meta) => Ok(meta),
545             Meta::Path(path) => Err(crate::error::new2(
546                 path.segments.first().unwrap().ident.span(),
547                 path.segments.last().unwrap().ident.span(),
548                 format!(
549                     "expected a value for this attribute: `{} = ...`",
550                     parsing::DisplayPath(path),
551                 ),
552             )),
553             Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")),
554         }
555     }
556 }
557 
558 impl MetaList {
559     /// See [`Attribute::parse_args`].
560     #[cfg(feature = "parsing")]
561     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_args<T: Parse>(&self) -> Result<T>562     pub fn parse_args<T: Parse>(&self) -> Result<T> {
563         self.parse_args_with(T::parse)
564     }
565 
566     /// See [`Attribute::parse_args_with`].
567     #[cfg(feature = "parsing")]
568     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output>569     pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
570         let scope = self.delimiter.span().close();
571         crate::parse::parse_scoped(parser, scope, self.tokens.clone())
572     }
573 
574     /// See [`Attribute::parse_nested_meta`].
575     #[cfg(feature = "parsing")]
576     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
parse_nested_meta( &self, logic: impl FnMut(ParseNestedMeta) -> Result<()>, ) -> Result<()>577     pub fn parse_nested_meta(
578         &self,
579         logic: impl FnMut(ParseNestedMeta) -> Result<()>,
580     ) -> Result<()> {
581         self.parse_args_with(meta::parser(logic))
582     }
583 }
584 
585 pub(crate) trait FilterAttrs<'a> {
586     type Ret: Iterator<Item = &'a Attribute>;
587 
outer(self) -> Self::Ret588     fn outer(self) -> Self::Ret;
inner(self) -> Self::Ret589     fn inner(self) -> Self::Ret;
590 }
591 
592 impl<'a> FilterAttrs<'a> for &'a [Attribute] {
593     type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>;
594 
outer(self) -> Self::Ret595     fn outer(self) -> Self::Ret {
596         fn is_outer(attr: &&Attribute) -> bool {
597             match attr.style {
598                 AttrStyle::Outer => true,
599                 AttrStyle::Inner(_) => false,
600             }
601         }
602         self.iter().filter(is_outer)
603     }
604 
inner(self) -> Self::Ret605     fn inner(self) -> Self::Ret {
606         fn is_inner(attr: &&Attribute) -> bool {
607             match attr.style {
608                 AttrStyle::Inner(_) => true,
609                 AttrStyle::Outer => false,
610             }
611         }
612         self.iter().filter(is_inner)
613     }
614 }
615 
616 #[cfg(feature = "parsing")]
617 pub(crate) mod parsing {
618     use super::*;
619     use crate::parse::discouraged::Speculative as _;
620     use crate::parse::{Parse, ParseStream, Result};
621     use std::fmt::{self, Display};
622 
parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()>623     pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
624         while input.peek(Token![#]) && input.peek2(Token![!]) {
625             attrs.push(input.call(parsing::single_parse_inner)?);
626         }
627         Ok(())
628     }
629 
single_parse_inner(input: ParseStream) -> Result<Attribute>630     pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
631         let content;
632         Ok(Attribute {
633             pound_token: input.parse()?,
634             style: AttrStyle::Inner(input.parse()?),
635             bracket_token: bracketed!(content in input),
636             meta: content.parse()?,
637         })
638     }
639 
single_parse_outer(input: ParseStream) -> Result<Attribute>640     pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
641         let content;
642         Ok(Attribute {
643             pound_token: input.parse()?,
644             style: AttrStyle::Outer,
645             bracket_token: bracketed!(content in input),
646             meta: content.parse()?,
647         })
648     }
649 
650     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
651     impl Parse for Meta {
parse(input: ParseStream) -> Result<Self>652         fn parse(input: ParseStream) -> Result<Self> {
653             let path = input.call(Path::parse_mod_style)?;
654             parse_meta_after_path(path, input)
655         }
656     }
657 
658     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
659     impl Parse for MetaList {
parse(input: ParseStream) -> Result<Self>660         fn parse(input: ParseStream) -> Result<Self> {
661             let path = input.call(Path::parse_mod_style)?;
662             parse_meta_list_after_path(path, input)
663         }
664     }
665 
666     #[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
667     impl Parse for MetaNameValue {
parse(input: ParseStream) -> Result<Self>668         fn parse(input: ParseStream) -> Result<Self> {
669             let path = input.call(Path::parse_mod_style)?;
670             parse_meta_name_value_after_path(path, input)
671         }
672     }
673 
parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta>674     pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
675         if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) {
676             parse_meta_list_after_path(path, input).map(Meta::List)
677         } else if input.peek(Token![=]) {
678             parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
679         } else {
680             Ok(Meta::Path(path))
681         }
682     }
683 
parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList>684     fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
685         let (delimiter, tokens) = mac::parse_delimiter(input)?;
686         Ok(MetaList {
687             path,
688             delimiter,
689             tokens,
690         })
691     }
692 
parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue>693     fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
694         let eq_token: Token![=] = input.parse()?;
695         let ahead = input.fork();
696         let lit: Option<Lit> = ahead.parse()?;
697         let value = if let (Some(lit), true) = (lit, ahead.is_empty()) {
698             input.advance_to(&ahead);
699             Expr::Lit(ExprLit {
700                 attrs: Vec::new(),
701                 lit,
702             })
703         } else if input.peek(Token![#]) && input.peek2(token::Bracket) {
704             return Err(input.error("unexpected attribute inside of attribute"));
705         } else {
706             input.parse()?
707         };
708         Ok(MetaNameValue {
709             path,
710             eq_token,
711             value,
712         })
713     }
714 
715     pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
716 
717     impl<'a> Display for DisplayAttrStyle<'a> {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result718         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
719             formatter.write_str(match self.0 {
720                 AttrStyle::Outer => "#",
721                 AttrStyle::Inner(_) => "#!",
722             })
723         }
724     }
725 
726     pub(super) struct DisplayPath<'a>(pub &'a Path);
727 
728     impl<'a> Display for DisplayPath<'a> {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result729         fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
730             for (i, segment) in self.0.segments.iter().enumerate() {
731                 if i > 0 || self.0.leading_colon.is_some() {
732                     formatter.write_str("::")?;
733                 }
734                 write!(formatter, "{}", segment.ident)?;
735             }
736             Ok(())
737         }
738     }
739 }
740 
741 #[cfg(feature = "printing")]
742 mod printing {
743     use super::*;
744     use proc_macro2::TokenStream;
745     use quote::ToTokens;
746 
747     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
748     impl ToTokens for Attribute {
to_tokens(&self, tokens: &mut TokenStream)749         fn to_tokens(&self, tokens: &mut TokenStream) {
750             self.pound_token.to_tokens(tokens);
751             if let AttrStyle::Inner(b) = &self.style {
752                 b.to_tokens(tokens);
753             }
754             self.bracket_token.surround(tokens, |tokens| {
755                 self.meta.to_tokens(tokens);
756             });
757         }
758     }
759 
760     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
761     impl ToTokens for MetaList {
to_tokens(&self, tokens: &mut TokenStream)762         fn to_tokens(&self, tokens: &mut TokenStream) {
763             self.path.to_tokens(tokens);
764             self.delimiter.surround(tokens, self.tokens.clone());
765         }
766     }
767 
768     #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))]
769     impl ToTokens for MetaNameValue {
to_tokens(&self, tokens: &mut TokenStream)770         fn to_tokens(&self, tokens: &mut TokenStream) {
771             self.path.to_tokens(tokens);
772             self.eq_token.to_tokens(tokens);
773             self.value.to_tokens(tokens);
774         }
775     }
776 }
777