at master 4.8 kB view raw
1// SPDX-License-Identifier: Apache-2.0 OR MIT 2 3/// Formatting macro for constructing `Ident`s. 4/// 5/// <br> 6/// 7/// # Syntax 8/// 9/// Syntax is copied from the [`format!`] macro, supporting both positional and 10/// named arguments. 11/// 12/// Only a limited set of formatting traits are supported. The current mapping 13/// of format types to traits is: 14/// 15/// * `{}` ⇒ [`IdentFragment`] 16/// * `{:o}` ⇒ [`Octal`](std::fmt::Octal) 17/// * `{:x}` ⇒ [`LowerHex`](std::fmt::LowerHex) 18/// * `{:X}` ⇒ [`UpperHex`](std::fmt::UpperHex) 19/// * `{:b}` ⇒ [`Binary`](std::fmt::Binary) 20/// 21/// See [`std::fmt`] for more information. 22/// 23/// <br> 24/// 25/// # IdentFragment 26/// 27/// Unlike `format!`, this macro uses the [`IdentFragment`] formatting trait by 28/// default. This trait is like `Display`, with a few differences: 29/// 30/// * `IdentFragment` is only implemented for a limited set of types, such as 31/// unsigned integers and strings. 32/// * [`Ident`] arguments will have their `r#` prefixes stripped, if present. 33/// 34/// [`IdentFragment`]: crate::IdentFragment 35/// [`Ident`]: proc_macro2::Ident 36/// 37/// <br> 38/// 39/// # Hygiene 40/// 41/// The [`Span`] of the first `Ident` argument is used as the span of the final 42/// identifier, falling back to [`Span::call_site`] when no identifiers are 43/// provided. 44/// 45/// ``` 46/// # use quote::format_ident; 47/// # let ident = format_ident!("Ident"); 48/// // If `ident` is an Ident, the span of `my_ident` will be inherited from it. 49/// let my_ident = format_ident!("My{}{}", ident, "IsCool"); 50/// assert_eq!(my_ident, "MyIdentIsCool"); 51/// ``` 52/// 53/// Alternatively, the span can be overridden by passing the `span` named 54/// argument. 55/// 56/// ``` 57/// # use quote::format_ident; 58/// # const IGNORE_TOKENS: &'static str = stringify! { 59/// let my_span = /* ... */; 60/// # }; 61/// # let my_span = proc_macro2::Span::call_site(); 62/// format_ident!("MyIdent", span = my_span); 63/// ``` 64/// 65/// [`Span`]: proc_macro2::Span 66/// [`Span::call_site`]: proc_macro2::Span::call_site 67/// 68/// <p><br></p> 69/// 70/// # Panics 71/// 72/// This method will panic if the resulting formatted string is not a valid 73/// identifier. 74/// 75/// <br> 76/// 77/// # Examples 78/// 79/// Composing raw and non-raw identifiers: 80/// ``` 81/// # use quote::format_ident; 82/// let my_ident = format_ident!("My{}", "Ident"); 83/// assert_eq!(my_ident, "MyIdent"); 84/// 85/// let raw = format_ident!("r#Raw"); 86/// assert_eq!(raw, "r#Raw"); 87/// 88/// let my_ident_raw = format_ident!("{}Is{}", my_ident, raw); 89/// assert_eq!(my_ident_raw, "MyIdentIsRaw"); 90/// ``` 91/// 92/// Integer formatting options: 93/// ``` 94/// # use quote::format_ident; 95/// let num: u32 = 10; 96/// 97/// let decimal = format_ident!("Id_{}", num); 98/// assert_eq!(decimal, "Id_10"); 99/// 100/// let octal = format_ident!("Id_{:o}", num); 101/// assert_eq!(octal, "Id_12"); 102/// 103/// let binary = format_ident!("Id_{:b}", num); 104/// assert_eq!(binary, "Id_1010"); 105/// 106/// let lower_hex = format_ident!("Id_{:x}", num); 107/// assert_eq!(lower_hex, "Id_a"); 108/// 109/// let upper_hex = format_ident!("Id_{:X}", num); 110/// assert_eq!(upper_hex, "Id_A"); 111/// ``` 112#[macro_export] 113macro_rules! format_ident { 114 ($fmt:expr) => { 115 $crate::format_ident_impl!([ 116 $crate::__private::Option::None, 117 $fmt 118 ]) 119 }; 120 121 ($fmt:expr, $($rest:tt)*) => { 122 $crate::format_ident_impl!([ 123 $crate::__private::Option::None, 124 $fmt 125 ] $($rest)*) 126 }; 127} 128 129#[macro_export] 130#[doc(hidden)] 131macro_rules! format_ident_impl { 132 // Final state 133 ([$span:expr, $($fmt:tt)*]) => { 134 $crate::__private::mk_ident( 135 &$crate::__private::format!($($fmt)*), 136 $span, 137 ) 138 }; 139 140 // Span argument 141 ([$old:expr, $($fmt:tt)*] span = $span:expr) => { 142 $crate::format_ident_impl!([$old, $($fmt)*] span = $span,) 143 }; 144 ([$old:expr, $($fmt:tt)*] span = $span:expr, $($rest:tt)*) => { 145 $crate::format_ident_impl!([ 146 $crate::__private::Option::Some::<$crate::__private::Span>($span), 147 $($fmt)* 148 ] $($rest)*) 149 }; 150 151 // Named argument 152 ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr) => { 153 $crate::format_ident_impl!([$span, $($fmt)*] $name = $arg,) 154 }; 155 ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr, $($rest:tt)*) => { 156 match $crate::__private::IdentFragmentAdapter(&$arg) { 157 arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, $name = arg] $($rest)*), 158 } 159 }; 160 161 // Positional argument 162 ([$span:expr, $($fmt:tt)*] $arg:expr) => { 163 $crate::format_ident_impl!([$span, $($fmt)*] $arg,) 164 }; 165 ([$span:expr, $($fmt:tt)*] $arg:expr, $($rest:tt)*) => { 166 match $crate::__private::IdentFragmentAdapter(&$arg) { 167 arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*), 168 } 169 }; 170}