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