1 use alloc::borrow::Cow;
2 use core::fmt;
3 use proc_macro2::{Ident, Span};
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
13 pub trait IdentFragment {
14     /// Format this value as an identifier fragment.
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result15     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.
span(&self) -> Option<Span>20     fn span(&self) -> Option<Span> {
21         None
22     }
23 }
24 
25 impl<T: IdentFragment + ?Sized> IdentFragment for &T {
span(&self) -> Option<Span>26     fn span(&self) -> Option<Span> {
27         <T as IdentFragment>::span(*self)
28     }
29 
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result30     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31         IdentFragment::fmt(*self, f)
32     }
33 }
34 
35 impl<T: IdentFragment + ?Sized> IdentFragment for &mut T {
span(&self) -> Option<Span>36     fn span(&self) -> Option<Span> {
37         <T as IdentFragment>::span(*self)
38     }
39 
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result40     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
41         IdentFragment::fmt(*self, f)
42     }
43 }
44 
45 impl IdentFragment for Ident {
span(&self) -> Option<Span>46     fn span(&self) -> Option<Span> {
47         Some(self.span())
48     }
49 
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result50     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51         let id = self.to_string();
52         if let Some(id) = id.strip_prefix("r#") {
53             fmt::Display::fmt(id, f)
54         } else {
55             fmt::Display::fmt(&id[..], f)
56         }
57     }
58 }
59 
60 impl<T> IdentFragment for Cow<'_, T>
61 where
62     T: IdentFragment + ToOwned + ?Sized,
63 {
span(&self) -> Option<Span>64     fn span(&self) -> Option<Span> {
65         T::span(self)
66     }
67 
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result68     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.
75 macro_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 
87 ident_fragment_display!(bool, str, String, char);
88 ident_fragment_display!(u8, u16, u32, u64, u128, usize);
89