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