Skip to content

Commit 49f7550

Browse files
committed
Auto merge of #23162 - sfackler:debug-builders, r=alexcrichton
I've made some minor changes from the implementation attached to the RFC to try to minimize codegen. The methods now take `&Debug` trait objects rather than being parameterized and there are inlined stub methods that call to non-inlined methods to do the work. r? @alexcrichton cc @huonw for the `derive(Debug)` changes.
2 parents 8715a65 + 905a611 commit 49f7550

File tree

8 files changed

+867
-65
lines changed

8 files changed

+867
-65
lines changed

src/libcore/fmt/builders.rs

+301
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use prelude::*;
12+
use fmt::{self, Write, FlagV1};
13+
14+
struct PadAdapter<'a, 'b: 'a> {
15+
fmt: &'a mut fmt::Formatter<'b>,
16+
on_newline: bool,
17+
}
18+
19+
impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
20+
fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
21+
PadAdapter {
22+
fmt: fmt,
23+
on_newline: false,
24+
}
25+
}
26+
}
27+
28+
impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
29+
fn write_str(&mut self, mut s: &str) -> fmt::Result {
30+
while !s.is_empty() {
31+
if self.on_newline {
32+
try!(self.fmt.write_str(" "));
33+
}
34+
35+
let split = match s.find('\n') {
36+
Some(pos) => {
37+
self.on_newline = true;
38+
pos + 1
39+
}
40+
None => {
41+
self.on_newline = false;
42+
s.len()
43+
}
44+
};
45+
try!(self.fmt.write_str(&s[..split]));
46+
s = &s[split..];
47+
}
48+
49+
Ok(())
50+
}
51+
}
52+
53+
/// A struct to help with `fmt::Debug` implementations.
54+
///
55+
/// Constructed by the `Formatter::debug_struct` method.
56+
#[must_use]
57+
pub struct DebugStruct<'a, 'b: 'a> {
58+
fmt: &'a mut fmt::Formatter<'b>,
59+
result: fmt::Result,
60+
has_fields: bool,
61+
}
62+
63+
pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str)
64+
-> DebugStruct<'a, 'b> {
65+
let result = fmt.write_str(name);
66+
DebugStruct {
67+
fmt: fmt,
68+
result: result,
69+
has_fields: false,
70+
}
71+
}
72+
73+
impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
74+
/// Adds a new field to the generated struct output.
75+
#[unstable(feature = "debug_builders", reason = "method was just created")]
76+
pub fn field(mut self, name: &str, value: &fmt::Debug) -> DebugStruct<'a, 'b> {
77+
self.result = self.result.and_then(|_| {
78+
let prefix = if self.has_fields {
79+
","
80+
} else {
81+
" {"
82+
};
83+
84+
if self.is_pretty() {
85+
let mut writer = PadAdapter::new(self.fmt);
86+
fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value))
87+
} else {
88+
write!(self.fmt, "{} {}: {:?}", prefix, name, value)
89+
}
90+
});
91+
92+
self.has_fields = true;
93+
self
94+
}
95+
96+
/// Consumes the `DebugStruct`, finishing output and returning any error
97+
/// encountered.
98+
#[unstable(feature = "debug_builders", reason = "method was just created")]
99+
pub fn finish(mut self) -> fmt::Result {
100+
if self.has_fields {
101+
self.result = self.result.and_then(|_| {
102+
if self.is_pretty() {
103+
self.fmt.write_str("\n}")
104+
} else {
105+
self.fmt.write_str(" }")
106+
}
107+
});
108+
}
109+
self.result
110+
}
111+
112+
fn is_pretty(&self) -> bool {
113+
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
114+
}
115+
}
116+
117+
/// A struct to help with `fmt::Debug` implementations.
118+
///
119+
/// Constructed by the `Formatter::debug_tuple` method.
120+
#[must_use]
121+
pub struct DebugTuple<'a, 'b: 'a> {
122+
fmt: &'a mut fmt::Formatter<'b>,
123+
result: fmt::Result,
124+
has_fields: bool,
125+
}
126+
127+
pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugTuple<'a, 'b> {
128+
let result = fmt.write_str(name);
129+
DebugTuple {
130+
fmt: fmt,
131+
result: result,
132+
has_fields: false,
133+
}
134+
}
135+
136+
impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
137+
/// Adds a new field to the generated tuple struct output.
138+
#[unstable(feature = "debug_builders", reason = "method was just created")]
139+
pub fn field(mut self, value: &fmt::Debug) -> DebugTuple<'a, 'b> {
140+
self.result = self.result.and_then(|_| {
141+
let (prefix, space) = if self.has_fields {
142+
(",", " ")
143+
} else {
144+
("(", "")
145+
};
146+
147+
if self.is_pretty() {
148+
let mut writer = PadAdapter::new(self.fmt);
149+
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
150+
} else {
151+
write!(self.fmt, "{}{}{:?}", prefix, space, value)
152+
}
153+
});
154+
155+
self.has_fields = true;
156+
self
157+
}
158+
159+
/// Consumes the `DebugTuple`, finishing output and returning any error
160+
/// encountered.
161+
#[unstable(feature = "debug_builders", reason = "method was just created")]
162+
pub fn finish(mut self) -> fmt::Result {
163+
if self.has_fields {
164+
self.result = self.result.and_then(|_| {
165+
if self.is_pretty() {
166+
self.fmt.write_str("\n)")
167+
} else {
168+
self.fmt.write_str(")")
169+
}
170+
});
171+
}
172+
self.result
173+
}
174+
175+
fn is_pretty(&self) -> bool {
176+
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
177+
}
178+
}
179+
180+
/// A struct to help with `fmt::Debug` implementations.
181+
///
182+
/// Constructed by the `Formatter::debug_set` method.
183+
#[must_use]
184+
pub struct DebugSet<'a, 'b: 'a> {
185+
fmt: &'a mut fmt::Formatter<'b>,
186+
result: fmt::Result,
187+
has_fields: bool,
188+
}
189+
190+
pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugSet<'a, 'b> {
191+
let result = write!(fmt, "{} {{", name);
192+
DebugSet {
193+
fmt: fmt,
194+
result: result,
195+
has_fields: false,
196+
}
197+
}
198+
199+
impl<'a, 'b: 'a> DebugSet<'a, 'b> {
200+
/// Adds a new entry to the set output.
201+
#[unstable(feature = "debug_builders", reason = "method was just created")]
202+
pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> {
203+
self.result = self.result.and_then(|_| {
204+
let prefix = if self.has_fields {
205+
","
206+
} else {
207+
""
208+
};
209+
210+
if self.is_pretty() {
211+
let mut writer = PadAdapter::new(self.fmt);
212+
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
213+
} else {
214+
write!(self.fmt, "{} {:?}", prefix, entry)
215+
}
216+
});
217+
218+
self.has_fields = true;
219+
self
220+
}
221+
222+
/// Consumes the `DebugSet`, finishing output and returning any error
223+
/// encountered.
224+
#[unstable(feature = "debug_builders", reason = "method was just created")]
225+
pub fn finish(self) -> fmt::Result {
226+
self.result.and_then(|_| {
227+
let end = match (self.has_fields, self.is_pretty()) {
228+
(false, _) => "}",
229+
(true, false) => " }",
230+
(true, true) => "\n}",
231+
};
232+
self.fmt.write_str(end)
233+
})
234+
}
235+
236+
fn is_pretty(&self) -> bool {
237+
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
238+
}
239+
}
240+
241+
/// A struct to help with `fmt::Debug` implementations.
242+
///
243+
/// Constructed by the `Formatter::debug_map` method.
244+
#[must_use]
245+
pub struct DebugMap<'a, 'b: 'a> {
246+
fmt: &'a mut fmt::Formatter<'b>,
247+
result: fmt::Result,
248+
has_fields: bool,
249+
}
250+
251+
pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugMap<'a, 'b> {
252+
let result = write!(fmt, "{} {{", name);
253+
DebugMap {
254+
fmt: fmt,
255+
result: result,
256+
has_fields: false,
257+
}
258+
}
259+
260+
impl<'a, 'b: 'a> DebugMap<'a, 'b> {
261+
/// Adds a new entry to the map output.
262+
#[unstable(feature = "debug_builders", reason = "method was just created")]
263+
pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> {
264+
self.result = self.result.and_then(|_| {
265+
let prefix = if self.has_fields {
266+
","
267+
} else {
268+
""
269+
};
270+
271+
if self.is_pretty() {
272+
let mut writer = PadAdapter::new(self.fmt);
273+
fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
274+
} else {
275+
write!(self.fmt, "{} {:?}: {:?}", prefix, key, value)
276+
}
277+
});
278+
279+
self.has_fields = true;
280+
281+
self
282+
}
283+
284+
/// Consumes the `DebugMap`, finishing output and returning any error
285+
/// encountered.
286+
#[unstable(feature = "debug_builders", reason = "method was just created")]
287+
pub fn finish(self) -> fmt::Result {
288+
self.result.and_then(|_| {
289+
let end = match (self.has_fields, self.is_pretty()) {
290+
(false, _) => "}",
291+
(true, false) => " }",
292+
(true, true) => "\n}",
293+
};
294+
self.fmt.write_str(end)
295+
})
296+
}
297+
298+
fn is_pretty(&self) -> bool {
299+
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
300+
}
301+
}

0 commit comments

Comments
 (0)