debug3_derive/
lib.rs

1use quote::quote;
2use syn::Fields;
3use synstructure::{decl_derive, AddBounds};
4
5decl_derive!([Debug/*, attributes(debug_skip)*/] => derive_debug);
6
7// Based on
8// https://github.com/panicbit/custom_debug/blob/master/custom_debug_derive/src/lib.rs
9
10fn derive_debug(mut s: synstructure::Structure) -> proc_macro2::TokenStream {
11    // Handle ZST
12    if s.variants().is_empty() {
13        return s.gen_impl(quote! {
14            gen impl debug3::Debug for @Self {
15                fn fmt(&self, f: &mut debug3::Formatter) {
16                    match *self {}
17                }
18            }
19        });
20    }
21
22    s.add_bounds(AddBounds::Generics);
23
24    let variants = s.each_variant(|variant| {
25        let name = variant.ast().ident.to_string();
26
27        let debug_helper = match variant.ast().fields {
28            Fields::Named(_) | Fields::Unit => quote! {debug_struct},
29            Fields::Unnamed(_) => quote! {debug_tuple},
30        };
31
32        let variant_body = variant.bindings().iter().map(|b| {
33            let format = quote! {#b};
34
35            if let Some(ref name) = b.ast().ident.as_ref().map(<_>::to_string) {
36                quote! {
37                    s.field(#name, #format);
38                }
39            } else {
40                quote! {
41                    s.field(#format);
42                }
43            }
44        });
45
46        quote! {
47            let mut s = f.#debug_helper(#name);
48            #(#variant_body)*
49            s.finish()
50        }
51    });
52
53    s.gen_impl(quote! {
54        #[automatically_derived]
55        gen impl debug3::Debug for @Self {
56            fn fmt(&self, f: &mut debug3::Formatter) {
57                match self { #variants }
58            }
59        }
60    })
61}