1extern crate proc_macro;
2
3#[macro_use]
4extern crate quote;
5
6use proc_macro2::TokenStream;
7
8#[proc_macro_derive(DebugWith)]
9pub fn derive_debug_with(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
10 let input = syn::parse_macro_input!(input as syn::DeriveInput);
12
13 let name = &input.ident;
15
16 let debug_with = debug_with(&input);
18
19 let generics = add_trait_bounds(input.generics);
21 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
22
23 let expanded = quote! {
24 impl #impl_generics ::lark_debug_with::DebugWith for #name #ty_generics #where_clause {
26 fn fmt_with<Cx: ?Sized>(&self, cx: &Cx, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 #debug_with
28 }
29 }
30 };
31
32 if std::env::var("LARK_DEBUG_DERIVE").is_ok() {
33 eprintln!("expanded = {}", expanded);
34 }
35
36 proc_macro::TokenStream::from(expanded)
38}
39
40fn add_trait_bounds(mut generics: syn::Generics) -> syn::Generics {
42 for param in &mut generics.params {
44 if let syn::GenericParam::Type(ref mut type_param) = *param {
45 type_param
46 .bounds
47 .push(syn::parse_quote!(::lark_debug_with::DebugWith));
48 }
49 }
50
51 generics
52}
53
54fn debug_with(input: &syn::DeriveInput) -> TokenStream {
56 match &input.data {
57 syn::Data::Struct(data) => debug_with_struct(&input.ident, data),
58 syn::Data::Enum(data) => debug_with_variants(&input.ident, data),
59 syn::Data::Union(_) => unimplemented!(),
60 }
61}
62
63fn debug_with_variants(type_name: &syn::Ident, data: &syn::DataEnum) -> TokenStream {
64 let variant_streams: Vec<_> = data
65 .variants
66 .iter()
67 .map(|variant| {
68 let variant_name = &variant.ident;
69 match &variant.fields {
70 syn::Fields::Named(fields) => {
71 let fnames: &Vec<_> = &fields.named.iter().map(|f| &f.ident).collect();
72 let fnames1: &Vec<_> = fnames;
73 quote! {
74 #type_name :: #variant_name { #(#fnames),* } => {
75 fmt.debug_struct(stringify!(#variant_name))
76 #(
77 .field(stringify!(#fnames), &#fnames1.debug_with(cx))
78 )*
79 .finish()
80 }
81 }
82 }
83
84 syn::Fields::Unnamed(fields) => {
85 let all_names: Vec<syn::Ident> = vec![
86 syn::parse_quote!(a),
87 syn::parse_quote!(b),
88 syn::parse_quote!(c),
89 syn::parse_quote!(d),
90 ];
91 if fields.unnamed.len() > all_names.len() {
92 unimplemented!("too many variants")
93 }
94 let names = &all_names[0..fields.unnamed.len()];
95 quote! {
96 #type_name :: #variant_name(#(#names),*) => {
97 fmt.debug_tuple(stringify!(#variant_name))
98 #(
99 .field(&#names.debug_with(cx))
100 )*
101 .finish()
102 }
103 }
104 }
105
106 syn::Fields::Unit => {
107 quote! {
108 #type_name :: #variant_name => {
109 fmt.debug_struct(stringify!(#variant_name)).finish()
110 }
111 }
112 }
113 }
114 })
115 .collect();
116
117 quote! {
118 match self {
119 #(#variant_streams)*
120 }
121 }
122}
123
124fn debug_with_struct(type_name: &syn::Ident, data: &syn::DataStruct) -> TokenStream {
125 match &data.fields {
126 syn::Fields::Named(fields) => {
127 let fnames: &Vec<_> = &fields.named.iter().map(|f| &f.ident).collect();
131 let fnames1 = fnames;
132 quote! {
133 fmt.debug_struct(stringify!(#type_name))
134 #(
135 .field(stringify!(#fnames), &self.#fnames1.debug_with(cx))
136 )*
137 .finish()
138 }
139 }
140 syn::Fields::Unnamed(fields) => {
141 let indices = 0..fields.unnamed.len();
145 quote! {
146 fmt.debug_tuple(stringify!(#type_name))
147 #(
148 .field(&self.#indices.debug_with(cx))
149 )*
150 .finish()
151 }
152 }
153 syn::Fields::Unit => {
154 quote! {
155 fmt.debug_struct(stringify!(#type_name))
156 .finish()
157 }
158 }
159 }
160}