1#[cfg(feature = "parsing")]
2use crate::error::Error;
3#[cfg(feature = "parsing")]
4use crate::error::Result;
5use crate::expr::Expr;
6use crate::mac::MacroDelimiter;
7#[cfg(feature = "parsing")]
8use crate::meta::{self, ParseNestedMeta};
9#[cfg(feature = "parsing")]
10use crate::parse::{Parse, ParseStream, Parser};
11use crate::path::Path;
12use crate::token;
13#[cfg(feature = "parsing")]
14use alloc::format;
15#[cfg(feature = "parsing")]
16use alloc::vec::Vec;
17#[cfg(feature = "printing")]
18use core::iter;
19#[cfg(feature = "printing")]
20use core::slice;
21use proc_macro2::TokenStream;
22
23#[doc = r" An attribute, like `#[repr(transparent)]`."]
#[doc = r""]
#[doc = r" <br>"]
#[doc = r""]
#[doc = r" # Syntax"]
#[doc = r""]
#[doc = r" Rust has six types of attributes."]
#[doc = r""]
#[doc =
r" - Outer attributes like `#[repr(transparent)]`. These appear outside or"]
#[doc = r" in front of the item they describe."]
#[doc = r""]
#[doc =
r" - Inner attributes like `#![feature(proc_macro)]`. These appear inside"]
#[doc = r" of the item they describe, usually a module."]
#[doc = r""]
#[doc = r" - Outer one-line doc comments like `/// Example`."]
#[doc = r""]
#[doc = r" - Inner one-line doc comments like `//! Please file an issue`."]
#[doc = r""]
#[doc = r" - Outer documentation blocks `/** Example */`."]
#[doc = r""]
#[doc = r" - Inner documentation blocks `/*! Please file an issue */`."]
#[doc = r""]
#[doc =
r" The `style` field of type `AttrStyle` distinguishes whether an attribute"]
#[doc = r" is outer or inner."]
#[doc = r""]
#[doc =
r" Every attribute has a `path` that indicates the intended interpretation"]
#[doc =
r" of the rest of the attribute's contents. The path and the optional"]
#[doc =
r" additional contents are represented together in the `meta` field of the"]
#[doc = r" attribute in three possible varieties:"]
#[doc = r""]
#[doc =
r" - Meta::Path — attributes whose information content conveys just a"]
#[doc = r" path, for example the `#[test]` attribute."]
#[doc = r""]
#[doc =
r" - Meta::List — attributes that carry arbitrary tokens after the"]
#[doc =
r" path, surrounded by a delimiter (parenthesis, bracket, or brace). For"]
#[doc = r" example `#[derive(Copy)]` or `#[precondition(x < 5)]`."]
#[doc = r""]
#[doc =
r" - Meta::NameValue — attributes with an `=` sign after the path,"]
#[doc = r" followed by a Rust expression. For example `#[path ="]
#[doc = r#" "sys/windows.rs"]`."#]
#[doc = r""]
#[doc =
r" All doc comments are represented in the NameValue style with a path of"]
#[doc = r#" "doc", as this is how they are processed by the compiler and by"#]
#[doc = r" `macro_rules!` macros."]
#[doc = r""]
#[doc = r" ```text"]
#[doc = r" #[derive(Copy, Clone)]"]
#[doc = r" ~~~~~~Path"]
#[doc = r" ^^^^^^^^^^^^^^^^^^^Meta::List"]
#[doc = r""]
#[doc = r#" #[path = "sys/windows.rs"]"#]
#[doc = r" ~~~~Path"]
#[doc = r" ^^^^^^^^^^^^^^^^^^^^^^^Meta::NameValue"]
#[doc = r""]
#[doc = r" #[test]"]
#[doc = r" ^^^^Meta::Path"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" <br>"]
#[doc = r""]
#[doc = r" # Parsing from tokens to Attribute"]
#[doc = r""]
#[doc =
r" This type does not implement the [`Parse`] trait and thus cannot be"]
#[doc = r" parsed directly by [`ParseStream::parse`]. Instead use"]
#[doc = r" [`ParseStream::call`] with one of the two parser functions"]
#[doc =
r" [`Attribute::parse_outer`] or [`Attribute::parse_inner`] depending on"]
#[doc = r" which you intend to parse."]
#[doc = r""]
#[doc = r" [`Parse`]: crate::parse::Parse"]
#[doc = r" [`ParseStream::parse`]: crate::parse::ParseBuffer::parse"]
#[doc = r" [`ParseStream::call`]: crate::parse::ParseBuffer::call"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" use syn::{Attribute, Ident, Result, Token};"]
#[doc = r" use syn::parse::{Parse, ParseStream};"]
#[doc = r""]
#[doc = r" // Parses a unit struct with attributes."]
#[doc = r" //"]
#[doc = r#" // #[path = "s.tmpl"]"#]
#[doc = r" // struct S;"]
#[doc = r" struct UnitStruct {"]
#[doc = r" attrs: Vec<Attribute>,"]
#[doc = r" struct_token: Token![struct],"]
#[doc = r" name: Ident,"]
#[doc = r" semi_token: Token![;],"]
#[doc = r" }"]
#[doc = r""]
#[doc = r" impl Parse for UnitStruct {"]
#[doc = r" fn parse(input: ParseStream) -> Result<Self> {"]
#[doc = r" Ok(UnitStruct {"]
#[doc = r" attrs: input.call(Attribute::parse_outer)?,"]
#[doc = r" struct_token: input.parse()?,"]
#[doc = r" name: input.parse()?,"]
#[doc = r" semi_token: input.parse()?,"]
#[doc = r" })"]
#[doc = r" }"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" <p><br></p>"]
#[doc = r""]
#[doc = r" # Parsing from Attribute to structured arguments"]
#[doc = r""]
#[doc =
r" The grammar of attributes in Rust is very flexible, which makes the"]
#[doc =
r" syntax tree not that useful on its own. In particular, arguments of the"]
#[doc =
r" `Meta::List` variety of attribute are held in an arbitrary `tokens:"]
#[doc =
r" TokenStream`. Macros are expected to check the `path` of the attribute,"]
#[doc =
r" decide whether they recognize it, and then parse the remaining tokens"]
#[doc =
r" according to whatever grammar they wish to require for that kind of"]
#[doc =
r" attribute. Use [`parse_args()`] to parse those tokens into the expected"]
#[doc = r" data structure."]
#[doc = r""]
#[doc = r" [`parse_args()`]: Attribute::parse_args"]
#[doc = r""]
#[doc = r" <p><br></p>"]
#[doc = r""]
#[doc = r" # Doc comments"]
#[doc = r""]
#[doc =
r" The compiler transforms doc comments, such as `/// comment` and `/*!"]
#[doc =
r" comment */`, into attributes before macros are expanded. Each comment is"]
#[doc = r#" expanded into an attribute of the form `#[doc = r"comment"]`."#]
#[doc = r""]
#[doc =
r" As an example, the following `mod` items are expanded identically:"]
#[doc = r""]
#[doc = r" ```"]
#[doc = r" # use syn::{ItemMod, parse_quote};"]
#[doc = r" let doc: ItemMod = parse_quote! {"]
#[doc = r" /// Single line doc comments"]
#[doc = r" /// We write so many!"]
#[doc = r" /**"]
#[doc = r" * Multi-line comments..."]
#[doc = r" * May span many lines"]
#[doc = r" */"]
#[doc = r" mod example {"]
#[doc = r" //! Of course, they can be inner too"]
#[doc = r" /*! And fit in a single line */"]
#[doc = r" }"]
#[doc = r" };"]
#[doc = r" let attr: ItemMod = parse_quote! {"]
#[doc = r#" #[doc = r" Single line doc comments"]"#]
#[doc = r#" #[doc = r" We write so many!"]"#]
#[doc = r#" #[doc = r""#]
#[doc = r" * Multi-line comments..."]
#[doc = r" * May span many lines"]
#[doc = r#" "]"#]
#[doc = r" mod example {"]
#[doc = r#" #![doc = r" Of course, they can be inner too"]"#]
#[doc = r#" #![doc = r" And fit in a single line "]"#]
#[doc = r" }"]
#[doc = r" };"]
#[doc = r" assert_eq!(doc, attr);"]
#[doc = r" ```"]
pub struct Attribute {
pub pound_token: crate::token::Pound,
pub style: AttrStyle,
pub bracket_token: token::Bracket,
pub meta: Meta,
}ast_struct! {
24 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
177 pub struct Attribute {
178 pub pound_token: Token![#],
179 pub style: AttrStyle,
180 pub bracket_token: token::Bracket,
181 pub meta: Meta,
182 }
183}
184
185impl Attribute {
186 pub fn path(&self) -> &Path {
191 self.meta.path()
192 }
193
194 #[cfg(feature = "parsing")]
225 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
226 pub fn parse_args<T: Parse>(&self) -> Result<T> {
227 self.parse_args_with(T::parse)
228 }
229
230 #[cfg(feature = "parsing")]
248 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
249 pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
250 match &self.meta {
251 Meta::Path(path) => Err(crate::error::new2(
252 path.segments.first().unwrap().ident.span(),
253 path.segments.last().unwrap().ident.span(),
254 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected attribute arguments in parentheses: {0}[{1}(...)]",
parsing::DisplayAttrStyle(&self.style),
parsing::DisplayPath(path)))
})format!(
255 "expected attribute arguments in parentheses: {}[{}(...)]",
256 parsing::DisplayAttrStyle(&self.style),
257 parsing::DisplayPath(path),
258 ),
259 )),
260 Meta::NameValue(meta) => Err(Error::new(
261 meta.eq_token.span,
262 format_args!("expected parentheses: {0}[{1}(...)]",
parsing::DisplayAttrStyle(&self.style), parsing::DisplayPath(&meta.path))format_args!(
263 "expected parentheses: {}[{}(...)]",
264 parsing::DisplayAttrStyle(&self.style),
265 parsing::DisplayPath(&meta.path),
266 ),
267 )),
268 Meta::List(meta) => meta.parse_args_with(parser),
269 }
270 }
271
272 #[cfg(feature = "parsing")]
394 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
395 pub fn parse_nested_meta(
396 &self,
397 logic: impl FnMut(ParseNestedMeta) -> Result<()>,
398 ) -> Result<()> {
399 self.parse_args_with(meta::parser(logic))
400 }
401
402 #[cfg(feature = "parsing")]
409 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
410 pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
411 let mut attrs = Vec::new();
412 while input.peek(crate::token::PoundToken![#]) {
413 attrs.push(input.call(parsing::single_parse_outer)?);
414 }
415 Ok(attrs)
416 }
417
418 #[cfg(feature = "parsing")]
425 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
426 pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
427 let mut attrs = Vec::new();
428 parsing::parse_inner(input, &mut attrs)?;
429 Ok(attrs)
430 }
431}
432
433#[doc =
r" Distinguishes between attributes that decorate an item and attributes"]
#[doc = r" that are contained within an item."]
#[doc = r""]
#[doc = r" # Outer attributes"]
#[doc = r""]
#[doc = r" - `#[repr(transparent)]`"]
#[doc = r" - `/// # Example`"]
#[doc = r" - `/** Please file an issue */`"]
#[doc = r""]
#[doc = r" # Inner attributes"]
#[doc = r""]
#[doc = r" - `#![feature(proc_macro)]`"]
#[doc = r" - `//! # Example`"]
#[doc = r" - `/*! Please file an issue */`"]
pub enum AttrStyle { Outer, Inner(crate::token::Not), }ast_enum! {
434 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
449 pub enum AttrStyle {
450 Outer,
451 Inner(Token![!]),
452 }
453}
454
455#[doc = r" Content of a compile-time structured attribute."]
#[doc = r""]
#[doc = r" ## Path"]
#[doc = r""]
#[doc = r" A meta path is like the `test` in `#[test]`."]
#[doc = r""]
#[doc = r" ## List"]
#[doc = r""]
#[doc = r" A meta list is like the `derive(Copy)` in `#[derive(Copy)]`."]
#[doc = r""]
#[doc = r" ## NameValue"]
#[doc = r""]
#[doc = r#" A name-value meta is like the `path = "..."` in `#[path ="#]
#[doc = r#" "sys/windows.rs"]`."#]
#[doc = r""]
#[doc = r" # Syntax tree enum"]
#[doc = r""]
#[doc = r" This type is a [syntax tree enum]."]
#[doc = r""]
#[doc = r" [syntax tree enum]: crate::expr::Expr#syntax-tree-enums"]
pub enum Meta {
Path(Path),
#[doc =
r" A structured list within an attribute, like `derive(Copy, Clone)`."]
List(MetaList),
#[doc =
r#" A name-value pair within an attribute, like `feature = "nightly"`."#]
NameValue(MetaNameValue),
}ast_enum! {
456 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
477 pub enum Meta {
478 Path(Path),
479
480 List(MetaList),
482
483 NameValue(MetaNameValue),
485 }
486}
487
488#[doc =
r" A structured list within an attribute, like `derive(Copy, Clone)`."]
pub struct MetaList {
pub path: Path,
pub delimiter: MacroDelimiter,
pub tokens: TokenStream,
}ast_struct! {
489 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
491 pub struct MetaList {
492 pub path: Path,
493 pub delimiter: MacroDelimiter,
494 pub tokens: TokenStream,
495 }
496}
497
498#[doc =
r#" A name-value pair within an attribute, like `feature = "nightly"`."#]
pub struct MetaNameValue {
pub path: Path,
pub eq_token: crate::token::Eq,
pub value: Expr,
}ast_struct! {
499 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
501 pub struct MetaNameValue {
502 pub path: Path,
503 pub eq_token: Token![=],
504 pub value: Expr,
505 }
506}
507
508impl Meta {
509 pub fn path(&self) -> &Path {
514 match self {
515 Meta::Path(path) => path,
516 Meta::List(meta) => &meta.path,
517 Meta::NameValue(meta) => &meta.path,
518 }
519 }
520
521 #[cfg(feature = "parsing")]
523 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
524 pub fn require_path_only(&self) -> Result<&Path> {
525 let error_span = match self {
526 Meta::Path(path) => return Ok(path),
527 Meta::List(meta) => meta.delimiter.span().open(),
528 Meta::NameValue(meta) => meta.eq_token.span,
529 };
530 Err(Error::new(error_span, "unexpected token in attribute"))
531 }
532
533 #[cfg(feature = "parsing")]
535 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
536 pub fn require_list(&self) -> Result<&MetaList> {
537 match self {
538 Meta::List(meta) => Ok(meta),
539 Meta::Path(path) => Err(crate::error::new2(
540 path.segments.first().unwrap().ident.span(),
541 path.segments.last().unwrap().ident.span(),
542 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected attribute arguments in parentheses: `{0}(...)`",
parsing::DisplayPath(path)))
})format!(
543 "expected attribute arguments in parentheses: `{}(...)`",
544 parsing::DisplayPath(path),
545 ),
546 )),
547 Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")),
548 }
549 }
550
551 #[cfg(feature = "parsing")]
553 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
554 pub fn require_name_value(&self) -> Result<&MetaNameValue> {
555 match self {
556 Meta::NameValue(meta) => Ok(meta),
557 Meta::Path(path) => Err(crate::error::new2(
558 path.segments.first().unwrap().ident.span(),
559 path.segments.last().unwrap().ident.span(),
560 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected a value for this attribute: `{0} = ...`",
parsing::DisplayPath(path)))
})format!(
561 "expected a value for this attribute: `{} = ...`",
562 parsing::DisplayPath(path),
563 ),
564 )),
565 Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")),
566 }
567 }
568}
569
570impl MetaList {
571 #[cfg(feature = "parsing")]
573 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
574 pub fn parse_args<T: Parse>(&self) -> Result<T> {
575 self.parse_args_with(T::parse)
576 }
577
578 #[cfg(feature = "parsing")]
580 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
581 pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
582 let scope = self.delimiter.span().close();
583 crate::parse::parse_scoped(parser, scope, self.tokens.clone())
584 }
585
586 #[cfg(feature = "parsing")]
588 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
589 pub fn parse_nested_meta(
590 &self,
591 logic: impl FnMut(ParseNestedMeta) -> Result<()>,
592 ) -> Result<()> {
593 self.parse_args_with(meta::parser(logic))
594 }
595}
596
597#[cfg(feature = "printing")]
598pub(crate) trait FilterAttrs<'a> {
599 type Ret: Iterator<Item = &'a Attribute>;
600
601 fn outer(self) -> Self::Ret;
602 #[cfg(feature = "full")]
603 fn inner(self) -> Self::Ret;
604}
605
606#[cfg(feature = "printing")]
607impl<'a> FilterAttrs<'a> for &'a [Attribute] {
608 type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>;
609
610 fn outer(self) -> Self::Ret {
611 fn is_outer(attr: &&Attribute) -> bool {
612 match attr.style {
613 AttrStyle::Outer => true,
614 AttrStyle::Inner(_) => false,
615 }
616 }
617 self.iter().filter(is_outer)
618 }
619
620 #[cfg(feature = "full")]
621 fn inner(self) -> Self::Ret {
622 fn is_inner(attr: &&Attribute) -> bool {
623 match attr.style {
624 AttrStyle::Inner(_) => true,
625 AttrStyle::Outer => false,
626 }
627 }
628 self.iter().filter(is_inner)
629 }
630}
631
632impl From<Path> for Meta {
633 fn from(meta: Path) -> Meta {
634 Meta::Path(meta)
635 }
636}
637
638impl From<MetaList> for Meta {
639 fn from(meta: MetaList) -> Meta {
640 Meta::List(meta)
641 }
642}
643
644impl From<MetaNameValue> for Meta {
645 fn from(meta: MetaNameValue) -> Meta {
646 Meta::NameValue(meta)
647 }
648}
649
650#[cfg(feature = "parsing")]
651pub(crate) mod parsing {
652 use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
653 use crate::error::Result;
654 use crate::expr::{Expr, ExprLit};
655 use crate::lit::Lit;
656 use crate::parse::discouraged::Speculative as _;
657 use crate::parse::{Parse, ParseStream};
658 use crate::path::Path;
659 use crate::{mac, token};
660 use alloc::vec::Vec;
661 use core::fmt::{self, Display};
662 use proc_macro2::Ident;
663
664 pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
665 while input.peek(crate::token::PoundToken![#]) && input.peek2(crate::token::NotToken![!]) {
666 attrs.push(input.call(single_parse_inner)?);
667 }
668 Ok(())
669 }
670
671 pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
672 let content;
673 Ok(Attribute {
674 pound_token: input.parse()?,
675 style: AttrStyle::Inner(input.parse()?),
676 bracket_token: match crate::__private::parse_brackets(&input) {
crate::__private::Ok(brackets) => {
content = brackets.content;
_ = content;
brackets.token
}
crate::__private::Err(error) => { return crate::__private::Err(error); }
}bracketed!(content in input),
677 meta: content.parse()?,
678 })
679 }
680
681 pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
682 let content;
683 Ok(Attribute {
684 pound_token: input.parse()?,
685 style: AttrStyle::Outer,
686 bracket_token: match crate::__private::parse_brackets(&input) {
crate::__private::Ok(brackets) => {
content = brackets.content;
_ = content;
brackets.token
}
crate::__private::Err(error) => { return crate::__private::Err(error); }
}bracketed!(content in input),
687 meta: content.parse()?,
688 })
689 }
690
691 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
692 impl Parse for Meta {
693 fn parse(input: ParseStream) -> Result<Self> {
694 let path = parse_outermost_meta_path(input)?;
695 parse_meta_after_path(path, input)
696 }
697 }
698
699 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
700 impl Parse for MetaList {
701 fn parse(input: ParseStream) -> Result<Self> {
702 let path = parse_outermost_meta_path(input)?;
703 parse_meta_list_after_path(path, input)
704 }
705 }
706
707 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
708 impl Parse for MetaNameValue {
709 fn parse(input: ParseStream) -> Result<Self> {
710 let path = parse_outermost_meta_path(input)?;
711 parse_meta_name_value_after_path(path, input)
712 }
713 }
714
715 fn parse_outermost_meta_path(input: ParseStream) -> Result<Path> {
718 if input.peek(crate::token::UnsafeToken![unsafe]) {
719 let unsafe_token: crate::token::UnsafeToken![unsafe] = input.parse()?;
720 Ok(Path::from(Ident::new("unsafe", unsafe_token.span)))
721 } else {
722 Path::parse_mod_style(input)
723 }
724 }
725
726 pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
727 if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) {
728 parse_meta_list_after_path(path, input).map(Meta::List)
729 } else if input.peek(crate::token::EqToken![=]) && !input.peek(crate::token::EqEqToken![==]) && !input.peek(crate::token::FatArrowToken![=>]) {
730 parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
731 } else {
732 Ok(Meta::Path(path))
733 }
734 }
735
736 fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
737 let (delimiter, tokens) = mac::parse_delimiter(input)?;
738 Ok(MetaList {
739 path,
740 delimiter,
741 tokens,
742 })
743 }
744
745 fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
746 let eq_token: crate::token::EqToken![=] = input.parse()?;
747 let ahead = input.fork();
748 let lit: Option<Lit> = ahead.parse()?;
749 let value = if let (Some(lit), true) = (lit, ahead.is_empty()) {
750 input.advance_to(&ahead);
751 Expr::Lit(ExprLit {
752 attrs: Vec::new(),
753 lit,
754 })
755 } else if input.peek(crate::token::PoundToken![#]) && input.peek2(token::Bracket) {
756 return Err(input.error("unexpected attribute inside of attribute"));
757 } else {
758 input.parse()?
759 };
760 Ok(MetaNameValue {
761 path,
762 eq_token,
763 value,
764 })
765 }
766
767 pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
768
769 impl<'a> Display for DisplayAttrStyle<'a> {
770 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
771 formatter.write_str(match self.0 {
772 AttrStyle::Outer => "#",
773 AttrStyle::Inner(_) => "#!",
774 })
775 }
776 }
777
778 pub(super) struct DisplayPath<'a>(pub &'a Path);
779
780 impl<'a> Display for DisplayPath<'a> {
781 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
782 for (i, segment) in self.0.segments.iter().enumerate() {
783 if i > 0 || self.0.leading_colon.is_some() {
784 formatter.write_str("::")?;
785 }
786 formatter.write_fmt(format_args!("{0}", segment.ident))write!(formatter, "{}", segment.ident)?;
787 }
788 Ok(())
789 }
790 }
791}
792
793#[cfg(feature = "printing")]
794mod printing {
795 use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
796 use crate::path;
797 use crate::path::printing::PathStyle;
798 use proc_macro2::TokenStream;
799 use quote::ToTokens;
800
801 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
802 impl ToTokens for Attribute {
803 fn to_tokens(&self, tokens: &mut TokenStream) {
804 self.pound_token.to_tokens(tokens);
805 if let AttrStyle::Inner(b) = &self.style {
806 b.to_tokens(tokens);
807 }
808 self.bracket_token.surround(tokens, |tokens| {
809 self.meta.to_tokens(tokens);
810 });
811 }
812 }
813
814 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
815 impl ToTokens for Meta {
816 fn to_tokens(&self, tokens: &mut TokenStream) {
817 match self {
818 Meta::Path(path) => path::printing::print_path(tokens, path, PathStyle::Mod),
819 Meta::List(meta_list) => meta_list.to_tokens(tokens),
820 Meta::NameValue(meta_name_value) => meta_name_value.to_tokens(tokens),
821 }
822 }
823 }
824
825 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
826 impl ToTokens for MetaList {
827 fn to_tokens(&self, tokens: &mut TokenStream) {
828 path::printing::print_path(tokens, &self.path, PathStyle::Mod);
829 self.delimiter.surround(tokens, self.tokens.clone());
830 }
831 }
832
833 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
834 impl ToTokens for MetaNameValue {
835 fn to_tokens(&self, tokens: &mut TokenStream) {
836 path::printing::print_path(tokens, &self.path, PathStyle::Mod);
837 self.eq_token.to_tokens(tokens);
838 self.value.to_tokens(tokens);
839 }
840 }
841}