-
-
Notifications
You must be signed in to change notification settings - Fork 297
/
debug.rs
118 lines (108 loc) · 3.72 KB
/
debug.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use crate::{cfg, file, lookup};
use anyhow::Result;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};
use syn_codegen::{Data, Definitions, Node, Type};
const DEBUG_SRC: &str = "../src/gen/debug.rs";
fn expand_impl_body(defs: &Definitions, node: &Node) -> TokenStream {
let type_name = &node.ident;
let ident = Ident::new(type_name, Span::call_site());
match &node.data {
Data::Enum(variants) => {
let arms = variants.iter().map(|(variant_name, fields)| {
let variant = Ident::new(variant_name, Span::call_site());
if fields.is_empty() {
quote! {
#ident::#variant => formatter.write_str(#variant_name),
}
} else {
let pats = (0..fields.len())
.map(|i| format_ident!("v{}", i))
.collect::<Vec<_>>();
let mut cfg = None;
if node.ident == "Expr" {
if let Type::Syn(ty) = &fields[0] {
if !lookup::node(defs, ty).features.any.contains("derive") {
cfg = Some(quote!(#[cfg(feature = "full")]));
}
}
}
quote! {
#cfg
#ident::#variant(#(#pats),*) => {
let mut formatter = formatter.debug_tuple(#variant_name);
#(formatter.field(#pats);)*
formatter.finish()
}
}
}
});
let nonexhaustive = if node.exhaustive {
None
} else if node.ident == "Expr" {
Some(quote! {
#[cfg(any(syn_no_non_exhaustive, not(feature = "full")))]
_ => unreachable!(),
})
} else {
Some(quote! {
#[cfg(syn_no_non_exhaustive)]
_ => unreachable!(),
})
};
quote! {
match self {
#(#arms)*
#nonexhaustive
}
}
}
Data::Struct(fields) => {
let fields = fields.keys().map(|f| {
let ident = Ident::new(f, Span::call_site());
quote! {
formatter.field(#f, &self.#ident);
}
});
quote! {
let mut formatter = formatter.debug_struct(#type_name);
#(#fields)*
formatter.finish()
}
}
Data::Private => unreachable!(),
}
}
fn expand_impl(defs: &Definitions, node: &Node) -> TokenStream {
let manual_debug = node.data == Data::Private || node.ident == "LitBool";
if manual_debug {
return TokenStream::new();
}
let ident = Ident::new(&node.ident, Span::call_site());
let cfg_features = cfg::features(&node.features);
let body = expand_impl_body(defs, node);
quote! {
#cfg_features
#[cfg_attr(doc_cfg, doc(cfg(feature = "extra-traits")))]
impl Debug for #ident {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
#body
}
}
}
}
pub fn generate(defs: &Definitions) -> Result<()> {
let mut impls = TokenStream::new();
for node in &defs.types {
impls.extend(expand_impl(defs, node));
}
file::write(
DEBUG_SRC,
quote! {
use crate::*;
use std::fmt::{self, Debug};
#impls
},
)?;
Ok(())
}