1use core::fmt;
2use proc_macro2::{Ident, Span};
3use std::borrow::Cow;
4
5/// Specialized formatting trait used by `format_ident!`.
6///
7/// [`Ident`] arguments formatted using this trait will have their `r#` prefix
8/// stripped, if present.
9///
10/// See [`format_ident!`] for more information.
11///
12/// [`format_ident!`]: crate::format_ident
13pub trait IdentFragment {
14 /// Format this value as an identifier fragment.
15 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
16
17 /// Span associated with this `IdentFragment`.
18 ///
19 /// If non-`None`, may be inherited by formatted identifiers.
20 fn span(&self) -> Option<Span> {
21 None
22 }
23}
24
25impl<T: IdentFragment + ?Sized> IdentFragment for &T {
26 fn span(&self) -> Option<Span> {
27 <T as IdentFragment>::span(*self)
28 }
29
30 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31 IdentFragment::fmt(*self, f)
32 }
33}
34
35impl<T: IdentFragment + ?Sized> IdentFragment for &mut T {
36 fn span(&self) -> Option<Span> {
37 <T as IdentFragment>::span(*self)
38 }
39
40 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41 IdentFragment::fmt(*self, f)
42 }
43}
44
45impl IdentFragment for Ident {
46 fn span(&self) -> Option<Span> {
47 Some(self.span())
48 }
49
50 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51 let id: String = self.to_string();
52 if id.starts_with("r#") {
53 fmt::Display::fmt(&id[2..], f)
54 } else {
55 fmt::Display::fmt(&id[..], f)
56 }
57 }
58}
59
60impl<T> IdentFragment for Cow<'_, T>
61where
62 T: IdentFragment + ToOwned + ?Sized,
63{
64 fn span(&self) -> Option<Span> {
65 T::span(self)
66 }
67
68 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69 T::fmt(self, f)
70 }
71}
72
73// Limited set of types which this is implemented for, as we want to avoid types
74// which will often include non-identifier characters in their `Display` impl.
75macro_rules! ident_fragment_display {
76 ($($T:ty),*) => {
77 $(
78 impl IdentFragment for $T {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80 fmt::Display::fmt(self, f)
81 }
82 }
83 )*
84 };
85}
86
87ident_fragment_display!(bool, str, String, char);
88ident_fragment_display!(u8, u16, u32, u64, u128, usize);
89