reflect/
attr.rs

1use quote::ToTokens;
2use ref_cast::RefCast;
3use std::fmt::{self, Debug};
4use syn::{AttrStyle, Attribute, Meta};
5
6#[allow(clippy::ptr_arg)]
7pub fn debug(attrs: &Vec<Attribute>) -> &impl Debug {
8    Wrapper::ref_cast(attrs)
9}
10
11#[derive(RefCast)]
12#[repr(transparent)]
13struct Wrapper<T>(T);
14
15impl Debug for Wrapper<Vec<Attribute>> {
16    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17        f.debug_list()
18            .entries(self.0.iter().map(Wrapper::ref_cast))
19            .finish()
20    }
21}
22
23impl Debug for Wrapper<Attribute> {
24    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25        f.write_str("#")?;
26        match self.0.style {
27            AttrStyle::Outer => {}
28            AttrStyle::Inner(_) => f.write_str("!")?,
29        }
30        f.write_str("[")?;
31        for (i, segment) in self.0.path().segments.iter().enumerate() {
32            if i > 0 || self.0.path().leading_colon.is_some() {
33                f.write_str("::")?;
34            }
35            write!(f, "{}", segment.ident)?;
36        }
37        match &self.0.meta {
38            Meta::Path(_) => {}
39            Meta::List(meta) => write!(f, "({})", meta.tokens)?,
40            Meta::NameValue(meta) => write!(f, " = {}", meta.value.to_token_stream())?,
41        }
42        f.write_str("]")?;
43        Ok(())
44    }
45}
46
47#[test]
48fn test_debug() {
49    use syn::parse_quote;
50
51    let attrs = vec![
52        parse_quote!(#[derive(Debug)]),
53        parse_quote!(#[doc = "..."]),
54        parse_quote!(#[rustfmt::skip]),
55    ];
56
57    let actual = format!("{:#?}", debug(&attrs));
58    let expected = "[\
59                    \n    #[derive(Debug)],\
60                    \n    #[doc = \"...\"],\
61                    \n    #[rustfmt::skip],\
62                    \n]";
63    assert_eq!(actual, expected);
64}