quote/
format.rs

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]
110macro_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)]
128macro_rules! format_ident_impl {
129    // Final state
130    ([$span:expr, $($fmt:tt)*]) => {
131        $crate::__rt::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::__rt::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::__rt::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::__rt::IdentFragmentAdapter(&$arg) {
161            arg => $crate::format_ident_impl!([$span.or(arg.span()), $($fmt)*, arg] $($rest)*),
162        }
163    };
164}