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