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
119
use ast;
use ast::{MetaItem, Item, Expr,};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token;
use ptr::P;
pub fn expand_deriving_show<F>(cx: &mut ExtCtxt,
span: Span,
mitem: &MetaItem,
item: &Item,
push: F) where
F: FnOnce(P<Item>),
{
let fmtr = Ptr(box Literal(path_std!(cx, core::fmt::Formatter)),
Borrowed(None, ast::MutMutable));
let trait_def = TraitDef {
span: span,
attributes: Vec::new(),
path: path_std!(cx, core::fmt::Debug),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
methods: vec![
MethodDef {
name: "fmt",
generics: LifetimeBounds::empty(),
explicit_self: borrowed_explicit_self(),
args: vec!(fmtr),
ret_ty: Literal(path_std!(cx, core::fmt::Result)),
attributes: Vec::new(),
combine_substructure: combine_substructure(Box::new(|a, b, c| {
show_substructure(a, b, c)
}))
}
],
associated_types: Vec::new(),
};
trait_def.expand(cx, mitem, item, push)
}
fn show_substructure(cx: &mut ExtCtxt, span: Span,
substr: &Substructure) -> P<Expr> {
let name = match *substr.fields {
Struct(_) => substr.type_ident,
EnumMatching(_, v, _) => v.node.name,
EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
}
};
let span = Span { expn_id: cx.backtrace(), .. span };
let name = cx.expr_lit(span, ast::Lit_::LitStr(token::get_ident(name),
ast::StrStyle::CookedStr));
let mut expr = substr.nonself_args[0].clone();
match *substr.fields {
Struct(ref fields) | EnumMatching(_, _, ref fields) => {
if fields.is_empty() || fields[0].name.is_none() {
expr = cx.expr_method_call(span,
expr,
token::str_to_ident("debug_tuple"),
vec![name]);
for field in fields {
expr = cx.expr_method_call(span,
expr,
token::str_to_ident("field"),
vec![cx.expr_addr_of(field.span,
field.self_.clone())]);
}
} else {
expr = cx.expr_method_call(span,
expr,
token::str_to_ident("debug_struct"),
vec![name]);
for field in fields {
let name = cx.expr_lit(field.span, ast::Lit_::LitStr(
token::get_ident(field.name.clone().unwrap()),
ast::StrStyle::CookedStr));
expr = cx.expr_method_call(span,
expr,
token::str_to_ident("field"),
vec![name,
cx.expr_addr_of(field.span,
field.self_.clone())]);
}
}
}
_ => unreachable!()
}
cx.expr_method_call(span,
expr,
token::str_to_ident("finish"),
vec![])
}