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