1 | use core::fmt; |
2 | use proc_macro2::{Ident, Span}; |
3 | use 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 |
13 | pub 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 | |
25 | impl<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 | |
35 | impl<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 | |
45 | impl 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 | |
60 | impl<T> IdentFragment for Cow<'_, T> |
61 | where |
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. |
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 | |