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;
13use proc_macro2::TokenStream;
14#[cfg(feature = "printing")]
15use std::iter;
16#[cfg(feature = "printing")]
17use std::slice;
18
19#[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! {
20 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
173 pub struct Attribute {
174 pub pound_token: Token![#],
175 pub style: AttrStyle,
176 pub bracket_token: token::Bracket,
177 pub meta: Meta,
178 }
179}
180
181impl Attribute {
182 pub fn path(&self) -> &Path {
187 self.meta.path()
188 }
189
190 #[cfg(feature = "parsing")]
221 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
222 pub fn parse_args<T: Parse>(&self) -> Result<T> {
223 self.parse_args_with(T::parse)
224 }
225
226 #[cfg(feature = "parsing")]
244 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
245 pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
246 match &self.meta {
247 Meta::Path(path) => Err(crate::error::new2(
248 path.segments.first().unwrap().ident.span(),
249 path.segments.last().unwrap().ident.span(),
250 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected attribute arguments in parentheses: {0}[{1}(...)]",
parsing::DisplayAttrStyle(&self.style),
parsing::DisplayPath(path)))
})format!(
251 "expected attribute arguments in parentheses: {}[{}(...)]",
252 parsing::DisplayAttrStyle(&self.style),
253 parsing::DisplayPath(path),
254 ),
255 )),
256 Meta::NameValue(meta) => Err(Error::new(
257 meta.eq_token.span,
258 format_args!("expected parentheses: {0}[{1}(...)]",
parsing::DisplayAttrStyle(&self.style), parsing::DisplayPath(&meta.path))format_args!(
259 "expected parentheses: {}[{}(...)]",
260 parsing::DisplayAttrStyle(&self.style),
261 parsing::DisplayPath(&meta.path),
262 ),
263 )),
264 Meta::List(meta) => meta.parse_args_with(parser),
265 }
266 }
267
268 #[cfg(feature = "parsing")]
390 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
391 pub fn parse_nested_meta(
392 &self,
393 logic: impl FnMut(ParseNestedMeta) -> Result<()>,
394 ) -> Result<()> {
395 self.parse_args_with(meta::parser(logic))
396 }
397
398 #[cfg(feature = "parsing")]
405 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
406 pub fn parse_outer(input: ParseStream) -> Result<Vec<Self>> {
407 let mut attrs = Vec::new();
408 while input.peek(crate::token::PoundToken![#]) {
409 attrs.push(input.call(parsing::single_parse_outer)?);
410 }
411 Ok(attrs)
412 }
413
414 #[cfg(feature = "parsing")]
421 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
422 pub fn parse_inner(input: ParseStream) -> Result<Vec<Self>> {
423 let mut attrs = Vec::new();
424 parsing::parse_inner(input, &mut attrs)?;
425 Ok(attrs)
426 }
427}
428
429#[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! {
430 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
445 pub enum AttrStyle {
446 Outer,
447 Inner(Token![!]),
448 }
449}
450
451#[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! {
452 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
473 pub enum Meta {
474 Path(Path),
475
476 List(MetaList),
478
479 NameValue(MetaNameValue),
481 }
482}
483
484#[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! {
485 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
487 pub struct MetaList {
488 pub path: Path,
489 pub delimiter: MacroDelimiter,
490 pub tokens: TokenStream,
491 }
492}
493
494#[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! {
495 #[cfg_attr(docsrs, doc(cfg(any(feature = "full", feature = "derive"))))]
497 pub struct MetaNameValue {
498 pub path: Path,
499 pub eq_token: Token![=],
500 pub value: Expr,
501 }
502}
503
504impl Meta {
505 pub fn path(&self) -> &Path {
510 match self {
511 Meta::Path(path) => path,
512 Meta::List(meta) => &meta.path,
513 Meta::NameValue(meta) => &meta.path,
514 }
515 }
516
517 #[cfg(feature = "parsing")]
519 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
520 pub fn require_path_only(&self) -> Result<&Path> {
521 let error_span = match self {
522 Meta::Path(path) => return Ok(path),
523 Meta::List(meta) => meta.delimiter.span().open(),
524 Meta::NameValue(meta) => meta.eq_token.span,
525 };
526 Err(Error::new(error_span, "unexpected token in attribute"))
527 }
528
529 #[cfg(feature = "parsing")]
531 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
532 pub fn require_list(&self) -> Result<&MetaList> {
533 match self {
534 Meta::List(meta) => Ok(meta),
535 Meta::Path(path) => Err(crate::error::new2(
536 path.segments.first().unwrap().ident.span(),
537 path.segments.last().unwrap().ident.span(),
538 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected attribute arguments in parentheses: `{0}(...)`",
parsing::DisplayPath(path)))
})format!(
539 "expected attribute arguments in parentheses: `{}(...)`",
540 parsing::DisplayPath(path),
541 ),
542 )),
543 Meta::NameValue(meta) => Err(Error::new(meta.eq_token.span, "expected `(`")),
544 }
545 }
546
547 #[cfg(feature = "parsing")]
549 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
550 pub fn require_name_value(&self) -> Result<&MetaNameValue> {
551 match self {
552 Meta::NameValue(meta) => Ok(meta),
553 Meta::Path(path) => Err(crate::error::new2(
554 path.segments.first().unwrap().ident.span(),
555 path.segments.last().unwrap().ident.span(),
556 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("expected a value for this attribute: `{0} = ...`",
parsing::DisplayPath(path)))
})format!(
557 "expected a value for this attribute: `{} = ...`",
558 parsing::DisplayPath(path),
559 ),
560 )),
561 Meta::List(meta) => Err(Error::new(meta.delimiter.span().open(), "expected `=`")),
562 }
563 }
564}
565
566impl MetaList {
567 #[cfg(feature = "parsing")]
569 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
570 pub fn parse_args<T: Parse>(&self) -> Result<T> {
571 self.parse_args_with(T::parse)
572 }
573
574 #[cfg(feature = "parsing")]
576 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
577 pub fn parse_args_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
578 let scope = self.delimiter.span().close();
579 crate::parse::parse_scoped(parser, scope, self.tokens.clone())
580 }
581
582 #[cfg(feature = "parsing")]
584 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
585 pub fn parse_nested_meta(
586 &self,
587 logic: impl FnMut(ParseNestedMeta) -> Result<()>,
588 ) -> Result<()> {
589 self.parse_args_with(meta::parser(logic))
590 }
591}
592
593#[cfg(feature = "printing")]
594pub(crate) trait FilterAttrs<'a> {
595 type Ret: Iterator<Item = &'a Attribute>;
596
597 fn outer(self) -> Self::Ret;
598 #[cfg(feature = "full")]
599 fn inner(self) -> Self::Ret;
600}
601
602#[cfg(feature = "printing")]
603impl<'a> FilterAttrs<'a> for &'a [Attribute] {
604 type Ret = iter::Filter<slice::Iter<'a, Attribute>, fn(&&Attribute) -> bool>;
605
606 fn outer(self) -> Self::Ret {
607 fn is_outer(attr: &&Attribute) -> bool {
608 match attr.style {
609 AttrStyle::Outer => true,
610 AttrStyle::Inner(_) => false,
611 }
612 }
613 self.iter().filter(is_outer)
614 }
615
616 #[cfg(feature = "full")]
617 fn inner(self) -> Self::Ret {
618 fn is_inner(attr: &&Attribute) -> bool {
619 match attr.style {
620 AttrStyle::Inner(_) => true,
621 AttrStyle::Outer => false,
622 }
623 }
624 self.iter().filter(is_inner)
625 }
626}
627
628impl From<Path> for Meta {
629 fn from(meta: Path) -> Meta {
630 Meta::Path(meta)
631 }
632}
633
634impl From<MetaList> for Meta {
635 fn from(meta: MetaList) -> Meta {
636 Meta::List(meta)
637 }
638}
639
640impl From<MetaNameValue> for Meta {
641 fn from(meta: MetaNameValue) -> Meta {
642 Meta::NameValue(meta)
643 }
644}
645
646#[cfg(feature = "parsing")]
647pub(crate) mod parsing {
648 use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
649 use crate::error::Result;
650 use crate::expr::{Expr, ExprLit};
651 use crate::lit::Lit;
652 use crate::parse::discouraged::Speculative as _;
653 use crate::parse::{Parse, ParseStream};
654 use crate::path::Path;
655 use crate::{mac, token};
656 use proc_macro2::Ident;
657 use std::fmt::{self, Display};
658
659 pub(crate) fn parse_inner(input: ParseStream, attrs: &mut Vec<Attribute>) -> Result<()> {
660 while input.peek(crate::token::PoundToken![#]) && input.peek2(crate::token::NotToken![!]) {
661 attrs.push(input.call(single_parse_inner)?);
662 }
663 Ok(())
664 }
665
666 pub(crate) fn single_parse_inner(input: ParseStream) -> Result<Attribute> {
667 let content;
668 Ok(Attribute {
669 pound_token: input.parse()?,
670 style: AttrStyle::Inner(input.parse()?),
671 bracket_token: match crate::__private::parse_brackets(&input) {
crate::__private::Ok(brackets) => {
content = brackets.content;
brackets.token
}
crate::__private::Err(error) => { return crate::__private::Err(error); }
}bracketed!(content in input),
672 meta: content.parse()?,
673 })
674 }
675
676 pub(crate) fn single_parse_outer(input: ParseStream) -> Result<Attribute> {
677 let content;
678 Ok(Attribute {
679 pound_token: input.parse()?,
680 style: AttrStyle::Outer,
681 bracket_token: match crate::__private::parse_brackets(&input) {
crate::__private::Ok(brackets) => {
content = brackets.content;
brackets.token
}
crate::__private::Err(error) => { return crate::__private::Err(error); }
}bracketed!(content in input),
682 meta: content.parse()?,
683 })
684 }
685
686 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
687 impl Parse for Meta {
688 fn parse(input: ParseStream) -> Result<Self> {
689 let path = parse_outermost_meta_path(input)?;
690 parse_meta_after_path(path, input)
691 }
692 }
693
694 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
695 impl Parse for MetaList {
696 fn parse(input: ParseStream) -> Result<Self> {
697 let path = parse_outermost_meta_path(input)?;
698 parse_meta_list_after_path(path, input)
699 }
700 }
701
702 #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
703 impl Parse for MetaNameValue {
704 fn parse(input: ParseStream) -> Result<Self> {
705 let path = parse_outermost_meta_path(input)?;
706 parse_meta_name_value_after_path(path, input)
707 }
708 }
709
710 fn parse_outermost_meta_path(input: ParseStream) -> Result<Path> {
713 if input.peek(crate::token::UnsafeToken![unsafe]) {
714 let unsafe_token: Token![unsafe] = input.parse()?;
715 Ok(Path::from(Ident::new("unsafe", unsafe_token.span)))
716 } else {
717 Path::parse_mod_style(input)
718 }
719 }
720
721 pub(crate) fn parse_meta_after_path(path: Path, input: ParseStream) -> Result<Meta> {
722 if input.peek(token::Paren) || input.peek(token::Bracket) || input.peek(token::Brace) {
723 parse_meta_list_after_path(path, input).map(Meta::List)
724 } else if input.peek(crate::token::EqToken![=]) {
725 parse_meta_name_value_after_path(path, input).map(Meta::NameValue)
726 } else {
727 Ok(Meta::Path(path))
728 }
729 }
730
731 fn parse_meta_list_after_path(path: Path, input: ParseStream) -> Result<MetaList> {
732 let (delimiter, tokens) = mac::parse_delimiter(input)?;
733 Ok(MetaList {
734 path,
735 delimiter,
736 tokens,
737 })
738 }
739
740 fn parse_meta_name_value_after_path(path: Path, input: ParseStream) -> Result<MetaNameValue> {
741 let eq_token: Token![=] = input.parse()?;
742 let ahead = input.fork();
743 let lit: Option<Lit> = ahead.parse()?;
744 let value = if let (Some(lit), true) = (lit, ahead.is_empty()) {
745 input.advance_to(&ahead);
746 Expr::Lit(ExprLit {
747 attrs: Vec::new(),
748 lit,
749 })
750 } else if input.peek(crate::token::PoundToken![#]) && input.peek2(token::Bracket) {
751 return Err(input.error("unexpected attribute inside of attribute"));
752 } else {
753 input.parse()?
754 };
755 Ok(MetaNameValue {
756 path,
757 eq_token,
758 value,
759 })
760 }
761
762 pub(super) struct DisplayAttrStyle<'a>(pub &'a AttrStyle);
763
764 impl<'a> Display for DisplayAttrStyle<'a> {
765 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
766 formatter.write_str(match self.0 {
767 AttrStyle::Outer => "#",
768 AttrStyle::Inner(_) => "#!",
769 })
770 }
771 }
772
773 pub(super) struct DisplayPath<'a>(pub &'a Path);
774
775 impl<'a> Display for DisplayPath<'a> {
776 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
777 for (i, segment) in self.0.segments.iter().enumerate() {
778 if i > 0 || self.0.leading_colon.is_some() {
779 formatter.write_str("::")?;
780 }
781 formatter.write_fmt(format_args!("{0}", segment.ident))write!(formatter, "{}", segment.ident)?;
782 }
783 Ok(())
784 }
785 }
786}
787
788#[cfg(feature = "printing")]
789mod printing {
790 use crate::attr::{AttrStyle, Attribute, Meta, MetaList, MetaNameValue};
791 use crate::path;
792 use crate::path::printing::PathStyle;
793 use proc_macro2::TokenStream;
794 use quote::ToTokens;
795
796 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
797 impl ToTokens for Attribute {
798 fn to_tokens(&self, tokens: &mut TokenStream) {
799 self.pound_token.to_tokens(tokens);
800 if let AttrStyle::Inner(b) = &self.style {
801 b.to_tokens(tokens);
802 }
803 self.bracket_token.surround(tokens, |tokens| {
804 self.meta.to_tokens(tokens);
805 });
806 }
807 }
808
809 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
810 impl ToTokens for Meta {
811 fn to_tokens(&self, tokens: &mut TokenStream) {
812 match self {
813 Meta::Path(path) => path::printing::print_path(tokens, path, PathStyle::Mod),
814 Meta::List(meta_list) => meta_list.to_tokens(tokens),
815 Meta::NameValue(meta_name_value) => meta_name_value.to_tokens(tokens),
816 }
817 }
818 }
819
820 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
821 impl ToTokens for MetaList {
822 fn to_tokens(&self, tokens: &mut TokenStream) {
823 path::printing::print_path(tokens, &self.path, PathStyle::Mod);
824 self.delimiter.surround(tokens, self.tokens.clone());
825 }
826 }
827
828 #[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
829 impl ToTokens for MetaNameValue {
830 fn to_tokens(&self, tokens: &mut TokenStream) {
831 path::printing::print_path(tokens, &self.path, PathStyle::Mod);
832 self.eq_token.to_tokens(tokens);
833 self.value.to_tokens(tokens);
834 }
835 }
836}