xref: /linux/rust/quote/format.rs (revision 784faa8eca8270671e0ed6d9d21f04bbb80fc5f7)
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