Skip to main content

quote/
ident_fragment.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use alloc::borrow::Cow;
4use core::fmt;
5use 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
15pub 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
27impl<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
37impl<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
47impl 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
62impl<T> IdentFragment for Cow<'_, T>
63where
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.
77macro_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
89ident_fragment_display!(bool, str, String, char);
90ident_fragment_display!(u8, u16, u32, u64, u128, usize);