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/// [`IdentFragment`]: crate::IdentFragment
33/// [`Ident`]: proc_macro2::Ident
34///
35/// <br>
36///
37/// # Hygiene
38///
39/// The [`Span`] of the first `Ident` argument is used as the span of the final
40/// identifier, falling back to [`Span::call_site`] when no identifiers are
41/// provided.
42///
43/// ```
44/// # use quote::format_ident;
45/// # let ident = format_ident!("Ident");
46/// // If `ident` is an Ident, the span of `my_ident` will be inherited from it.
47/// let my_ident = format_ident!("My{}{}", ident, "IsCool");
48/// assert_eq!(my_ident, "MyIdentIsCool");
49/// ```
50///
51/// Alternatively, the span can be overridden by passing the `span` named
52/// argument.
53///
54/// ```
55/// # use quote::format_ident;
56/// # const IGNORE_TOKENS: &'static str = stringify! {
57/// let my_span = /* ... */;
58/// # };
59/// # let my_span = proc_macro2::Span::call_site();
60/// format_ident!("MyIdent", span = my_span);
61/// ```
62///
63/// [`Span`]: proc_macro2::Span
64/// [`Span::call_site`]: proc_macro2::Span::call_site
65///
66/// <p><br></p>
67///
68/// # Panics
69///
70/// This method will panic if the resulting formatted string is not a valid
71/// identifier.
72///
73/// <br>
74///
75/// # Examples
76///
77/// Composing raw and non-raw identifiers:
78/// ```
79/// # use quote::format_ident;
80/// let my_ident = format_ident!("My{}", "Ident");
81/// assert_eq!(my_ident, "MyIdent");
82///
83/// let raw = format_ident!("r#Raw");
84/// assert_eq!(raw, "r#Raw");
85///
86/// let my_ident_raw = format_ident!("{}Is{}", my_ident, raw);
87/// assert_eq!(my_ident_raw, "MyIdentIsRaw");
88/// ```
89///
90/// Integer formatting options:
91/// ```
92/// # use quote::format_ident;
93/// let num: u32 = 10;
94///
95/// let decimal = format_ident!("Id_{}", num);
96/// assert_eq!(decimal, "Id_10");
97///
98/// let octal = format_ident!("Id_{:o}", num);
99/// assert_eq!(octal, "Id_12");
100///
101/// let binary = format_ident!("Id_{:b}", num);
102/// assert_eq!(binary, "Id_1010");
103///
104/// let lower_hex = format_ident!("Id_{:x}", num);
105/// assert_eq!(lower_hex, "Id_a");
106///
107/// let upper_hex = format_ident!("Id_{:X}", num);
108/// assert_eq!(upper_hex, "Id_A");
109/// ```
110#[macro_export]
111macro_rules! format_ident {
112 ($fmt:expr) => {
113 $crate::format_ident_impl!([
114 $crate::__private::Option::None,
115 $fmt
116 ])
117 };
118
119 ($fmt:expr, $($rest:tt)*) => {
120 $crate::format_ident_impl!([
121 $crate::__private::Option::None,
122 $fmt
123 ] $($rest)*)
124 };
125}
126
127#[macro_export]
128#[doc(hidden)]
129macro_rules! format_ident_impl {
130 // Final state
131 ([$span:expr, $($fmt:tt)*]) => {
132 $crate::__private::mk_ident(
133 &$crate::__private::format!($($fmt)*),
134 $span,
135 )
136 };
137
138 // Span argument
139 ([$old:expr, $($fmt:tt)*] span = $span:expr) => {
140 $crate::format_ident_impl!([$old, $($fmt)*] span = $span,)
141 };
142 ([$old:expr, $($fmt:tt)*] span = $span:expr, $($rest:tt)*) => {
143 $crate::format_ident_impl!([
144 $crate::__private::Option::Some::<$crate::__private::Span>($span),
145 $($fmt)*
146 ] $($rest)*)
147 };
148
149 // Named argument
150 ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr) => {
151 $crate::format_ident_impl!([$span, $($fmt)*] $name = $arg,)
152 };
153 ([$span:expr, $($fmt:tt)*] $name:ident = $arg:expr, $($rest:tt)*) => {
154 match $crate::__private::IdentFragmentAdapter(&$arg) {
155 arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, $name = arg] $($rest)*),
156 }
157 };
158
159 // Positional argument
160 ([$span:expr, $($fmt:tt)*] $arg:expr) => {
161 $crate::format_ident_impl!([$span, $($fmt)*] $arg,)
162 };
163 ([$span:expr, $($fmt:tt)*] $arg:expr, $($rest:tt)*) => {
164 match $crate::__private::IdentFragmentAdapter(&$arg) {
165 arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*),
166 }
167 };
168}
169