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 — attributes whose information content conveys just a 43 /// path, for example the `#[test]` attribute. 44 /// 45 /// - Meta::List — 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 — 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