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}