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] 113 macro_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)] 131 macro_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 } 171