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