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