Skip to content

Commit 6dbf0ba

Browse files
committed
Auto merge of #46233 - SimonSapin:fmt-debuglist-flags, r=sfackler
Make fmt::DebugList and friends forward formatting parameters For example, formatting slice of integers with `{:04?}` should zero-pad each integer. This also affects every use of `#[derive(Debug)]`.
2 parents 588f7db + bf08789 commit 6dbf0ba

File tree

3 files changed

+134
-43
lines changed

3 files changed

+134
-43
lines changed

src/libcore/fmt/builders.rs

+58-43
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,29 @@
1010

1111
use fmt;
1212

13-
struct PadAdapter<'a, 'b: 'a> {
14-
fmt: &'a mut fmt::Formatter<'b>,
13+
struct PadAdapter<'a> {
14+
buf: &'a mut (fmt::Write + 'a),
1515
on_newline: bool,
1616
}
1717

18-
impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
19-
fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
20-
PadAdapter {
21-
fmt,
22-
on_newline: false,
23-
}
18+
impl<'a> PadAdapter<'a> {
19+
fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter, slot: &'b mut Option<Self>)
20+
-> fmt::Formatter<'b> {
21+
fmt.wrap_buf(move |buf| {
22+
*slot = Some(PadAdapter {
23+
buf,
24+
on_newline: false,
25+
});
26+
slot.as_mut().unwrap()
27+
})
2428
}
2529
}
2630

27-
impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
31+
impl<'a> fmt::Write for PadAdapter<'a> {
2832
fn write_str(&mut self, mut s: &str) -> fmt::Result {
2933
while !s.is_empty() {
3034
if self.on_newline {
31-
self.fmt.write_str(" ")?;
35+
self.buf.write_str(" ")?;
3236
}
3337

3438
let split = match s.find('\n') {
@@ -41,7 +45,7 @@ impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
4145
s.len()
4246
}
4347
};
44-
self.fmt.write_str(&s[..split])?;
48+
self.buf.write_str(&s[..split])?;
4549
s = &s[split..];
4650
}
4751

@@ -112,11 +116,16 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
112116
};
113117

114118
if self.is_pretty() {
115-
let mut writer = PadAdapter::new(self.fmt);
116-
fmt::write(&mut writer,
117-
format_args!("{}\n{}: {:#?}", prefix, name, value))
119+
let mut slot = None;
120+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
121+
writer.write_str(prefix)?;
122+
writer.write_str("\n")?;
123+
writer.write_str(name)?;
124+
writer.write_str(": ")?;
125+
value.fmt(&mut writer)
118126
} else {
119-
write!(self.fmt, "{} {}: {:?}", prefix, name, value)
127+
write!(self.fmt, "{} {}: ", prefix, name)?;
128+
value.fmt(self.fmt)
120129
}
121130
});
122131

@@ -204,10 +213,15 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
204213
};
205214

206215
if self.is_pretty() {
207-
let mut writer = PadAdapter::new(self.fmt);
208-
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
216+
let mut slot = None;
217+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
218+
writer.write_str(prefix)?;
219+
writer.write_str("\n")?;
220+
value.fmt(&mut writer)
209221
} else {
210-
write!(self.fmt, "{}{}{:?}", prefix, space, value)
222+
self.fmt.write_str(prefix)?;
223+
self.fmt.write_str(space)?;
224+
value.fmt(self.fmt)
211225
}
212226
});
213227

@@ -247,20 +261,19 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
247261
fn entry(&mut self, entry: &fmt::Debug) {
248262
self.result = self.result.and_then(|_| {
249263
if self.is_pretty() {
250-
let mut writer = PadAdapter::new(self.fmt);
251-
let prefix = if self.has_fields {
252-
","
264+
let mut slot = None;
265+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
266+
writer.write_str(if self.has_fields {
267+
",\n"
253268
} else {
254-
""
255-
};
256-
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
269+
"\n"
270+
})?;
271+
entry.fmt(&mut writer)
257272
} else {
258-
let prefix = if self.has_fields {
259-
", "
260-
} else {
261-
""
262-
};
263-
write!(self.fmt, "{}{:?}", prefix, entry)
273+
if self.has_fields {
274+
self.fmt.write_str(", ")?
275+
}
276+
entry.fmt(self.fmt)
264277
}
265278
});
266279

@@ -472,21 +485,23 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
472485
pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> {
473486
self.result = self.result.and_then(|_| {
474487
if self.is_pretty() {
475-
let mut writer = PadAdapter::new(self.fmt);
476-
let prefix = if self.has_fields {
477-
","
488+
let mut slot = None;
489+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
490+
writer.write_str(if self.has_fields {
491+
",\n"
478492
} else {
479-
""
480-
};
481-
fmt::write(&mut writer,
482-
format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
493+
"\n"
494+
})?;
495+
key.fmt(&mut writer)?;
496+
writer.write_str(": ")?;
497+
value.fmt(&mut writer)
483498
} else {
484-
let prefix = if self.has_fields {
485-
", "
486-
} else {
487-
""
488-
};
489-
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
499+
if self.has_fields {
500+
self.fmt.write_str(", ")?
501+
}
502+
key.fmt(self.fmt)?;
503+
self.fmt.write_str(": ")?;
504+
value.fmt(self.fmt)
490505
}
491506
});
492507

src/libcore/fmt/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,27 @@ pub fn write(output: &mut Write, args: Arguments) -> Result {
10341034
}
10351035

10361036
impl<'a> Formatter<'a> {
1037+
fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
1038+
where 'b: 'c, F: FnOnce(&'b mut (Write+'b)) -> &'c mut (Write+'c)
1039+
{
1040+
Formatter {
1041+
// We want to change this
1042+
buf: wrap(self.buf),
1043+
1044+
// And preserve these
1045+
flags: self.flags,
1046+
fill: self.fill,
1047+
align: self.align,
1048+
width: self.width,
1049+
precision: self.precision,
1050+
1051+
// These only exist in the struct for the `run` method,
1052+
// which won’t be used together with this method.
1053+
curarg: self.curarg.clone(),
1054+
args: self.args,
1055+
}
1056+
}
1057+
10371058
// First up is the collection of functions used to execute a format string
10381059
// at runtime. This consumes all of the compile-time statics generated by
10391060
// the format! syntax extension.

src/libcore/tests/fmt/builders.rs

+55
Original file line numberDiff line numberDiff line change
@@ -496,3 +496,58 @@ mod debug_list {
496496
format!("{:#?}", Bar));
497497
}
498498
}
499+
500+
#[test]
501+
fn test_formatting_parameters_are_forwarded() {
502+
use std::collections::{BTreeMap, BTreeSet};
503+
#[derive(Debug)]
504+
struct Foo {
505+
bar: u32,
506+
baz: u32,
507+
}
508+
let struct_ = Foo { bar: 1024, baz: 7 };
509+
let tuple = (1024, 7);
510+
let list = [1024, 7];
511+
let mut map = BTreeMap::new();
512+
map.insert("bar", 1024);
513+
map.insert("baz", 7);
514+
let mut set = BTreeSet::new();
515+
set.insert(1024);
516+
set.insert(7);
517+
518+
assert_eq!(format!("{:03?}", struct_), "Foo { bar: 1024, baz: 007 }");
519+
assert_eq!(format!("{:03?}", tuple), "(1024, 007)");
520+
assert_eq!(format!("{:03?}", list), "[1024, 007]");
521+
assert_eq!(format!("{:03?}", map), r#"{"bar": 1024, "baz": 007}"#);
522+
assert_eq!(format!("{:03?}", set), "{007, 1024}");
523+
assert_eq!(format!("{:#03?}", struct_), "
524+
Foo {
525+
bar: 1024,
526+
baz: 007
527+
}
528+
".trim());
529+
assert_eq!(format!("{:#03?}", tuple), "
530+
(
531+
1024,
532+
007
533+
)
534+
".trim());
535+
assert_eq!(format!("{:#03?}", list), "
536+
[
537+
1024,
538+
007
539+
]
540+
".trim());
541+
assert_eq!(format!("{:#03?}", map), r#"
542+
{
543+
"bar": 1024,
544+
"baz": 007
545+
}
546+
"#.trim());
547+
assert_eq!(format!("{:#03?}", set), "
548+
{
549+
007,
550+
1024
551+
}
552+
".trim());
553+
}

0 commit comments

Comments
 (0)