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