format.rs 4.7 KB

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