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)]`.
This commit is contained in:
commit
6dbf0ba691
3 changed files with 134 additions and 43 deletions
|
|
@ -10,25 +10,29 @@
|
|||
|
||||
use fmt;
|
||||
|
||||
struct PadAdapter<'a, 'b: 'a> {
|
||||
fmt: &'a mut fmt::Formatter<'b>,
|
||||
struct PadAdapter<'a> {
|
||||
buf: &'a mut (fmt::Write + 'a),
|
||||
on_newline: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> PadAdapter<'a, 'b> {
|
||||
fn new(fmt: &'a mut fmt::Formatter<'b>) -> PadAdapter<'a, 'b> {
|
||||
PadAdapter {
|
||||
fmt,
|
||||
on_newline: false,
|
||||
}
|
||||
impl<'a> PadAdapter<'a> {
|
||||
fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter, slot: &'b mut Option<Self>)
|
||||
-> fmt::Formatter<'b> {
|
||||
fmt.wrap_buf(move |buf| {
|
||||
*slot = Some(PadAdapter {
|
||||
buf,
|
||||
on_newline: false,
|
||||
});
|
||||
slot.as_mut().unwrap()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
|
||||
impl<'a> fmt::Write for PadAdapter<'a> {
|
||||
fn write_str(&mut self, mut s: &str) -> fmt::Result {
|
||||
while !s.is_empty() {
|
||||
if self.on_newline {
|
||||
self.fmt.write_str(" ")?;
|
||||
self.buf.write_str(" ")?;
|
||||
}
|
||||
|
||||
let split = match s.find('\n') {
|
||||
|
|
@ -41,7 +45,7 @@ impl<'a, 'b: 'a> fmt::Write for PadAdapter<'a, 'b> {
|
|||
s.len()
|
||||
}
|
||||
};
|
||||
self.fmt.write_str(&s[..split])?;
|
||||
self.buf.write_str(&s[..split])?;
|
||||
s = &s[split..];
|
||||
}
|
||||
|
||||
|
|
@ -112,11 +116,16 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
|
|||
};
|
||||
|
||||
if self.is_pretty() {
|
||||
let mut writer = PadAdapter::new(self.fmt);
|
||||
fmt::write(&mut writer,
|
||||
format_args!("{}\n{}: {:#?}", prefix, name, value))
|
||||
let mut slot = None;
|
||||
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
|
||||
writer.write_str(prefix)?;
|
||||
writer.write_str("\n")?;
|
||||
writer.write_str(name)?;
|
||||
writer.write_str(": ")?;
|
||||
value.fmt(&mut writer)
|
||||
} else {
|
||||
write!(self.fmt, "{} {}: {:?}", prefix, name, value)
|
||||
write!(self.fmt, "{} {}: ", prefix, name)?;
|
||||
value.fmt(self.fmt)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -204,10 +213,15 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
|
|||
};
|
||||
|
||||
if self.is_pretty() {
|
||||
let mut writer = PadAdapter::new(self.fmt);
|
||||
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, value))
|
||||
let mut slot = None;
|
||||
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
|
||||
writer.write_str(prefix)?;
|
||||
writer.write_str("\n")?;
|
||||
value.fmt(&mut writer)
|
||||
} else {
|
||||
write!(self.fmt, "{}{}{:?}", prefix, space, value)
|
||||
self.fmt.write_str(prefix)?;
|
||||
self.fmt.write_str(space)?;
|
||||
value.fmt(self.fmt)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -247,20 +261,19 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
|
|||
fn entry(&mut self, entry: &fmt::Debug) {
|
||||
self.result = self.result.and_then(|_| {
|
||||
if self.is_pretty() {
|
||||
let mut writer = PadAdapter::new(self.fmt);
|
||||
let prefix = if self.has_fields {
|
||||
","
|
||||
let mut slot = None;
|
||||
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
|
||||
writer.write_str(if self.has_fields {
|
||||
",\n"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
|
||||
"\n"
|
||||
})?;
|
||||
entry.fmt(&mut writer)
|
||||
} else {
|
||||
let prefix = if self.has_fields {
|
||||
", "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
write!(self.fmt, "{}{:?}", prefix, entry)
|
||||
if self.has_fields {
|
||||
self.fmt.write_str(", ")?
|
||||
}
|
||||
entry.fmt(self.fmt)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -472,21 +485,23 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
|
|||
pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> {
|
||||
self.result = self.result.and_then(|_| {
|
||||
if self.is_pretty() {
|
||||
let mut writer = PadAdapter::new(self.fmt);
|
||||
let prefix = if self.has_fields {
|
||||
","
|
||||
let mut slot = None;
|
||||
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
|
||||
writer.write_str(if self.has_fields {
|
||||
",\n"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
fmt::write(&mut writer,
|
||||
format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
|
||||
"\n"
|
||||
})?;
|
||||
key.fmt(&mut writer)?;
|
||||
writer.write_str(": ")?;
|
||||
value.fmt(&mut writer)
|
||||
} else {
|
||||
let prefix = if self.has_fields {
|
||||
", "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
|
||||
if self.has_fields {
|
||||
self.fmt.write_str(", ")?
|
||||
}
|
||||
key.fmt(self.fmt)?;
|
||||
self.fmt.write_str(": ")?;
|
||||
value.fmt(self.fmt)
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1034,6 +1034,27 @@ pub fn write(output: &mut Write, args: Arguments) -> Result {
|
|||
}
|
||||
|
||||
impl<'a> Formatter<'a> {
|
||||
fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c>
|
||||
where 'b: 'c, F: FnOnce(&'b mut (Write+'b)) -> &'c mut (Write+'c)
|
||||
{
|
||||
Formatter {
|
||||
// We want to change this
|
||||
buf: wrap(self.buf),
|
||||
|
||||
// And preserve these
|
||||
flags: self.flags,
|
||||
fill: self.fill,
|
||||
align: self.align,
|
||||
width: self.width,
|
||||
precision: self.precision,
|
||||
|
||||
// These only exist in the struct for the `run` method,
|
||||
// which won’t be used together with this method.
|
||||
curarg: self.curarg.clone(),
|
||||
args: self.args,
|
||||
}
|
||||
}
|
||||
|
||||
// First up is the collection of functions used to execute a format string
|
||||
// at runtime. This consumes all of the compile-time statics generated by
|
||||
// the format! syntax extension.
|
||||
|
|
|
|||
|
|
@ -496,3 +496,58 @@ mod debug_list {
|
|||
format!("{:#?}", Bar));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_formatting_parameters_are_forwarded() {
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
#[derive(Debug)]
|
||||
struct Foo {
|
||||
bar: u32,
|
||||
baz: u32,
|
||||
}
|
||||
let struct_ = Foo { bar: 1024, baz: 7 };
|
||||
let tuple = (1024, 7);
|
||||
let list = [1024, 7];
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert("bar", 1024);
|
||||
map.insert("baz", 7);
|
||||
let mut set = BTreeSet::new();
|
||||
set.insert(1024);
|
||||
set.insert(7);
|
||||
|
||||
assert_eq!(format!("{:03?}", struct_), "Foo { bar: 1024, baz: 007 }");
|
||||
assert_eq!(format!("{:03?}", tuple), "(1024, 007)");
|
||||
assert_eq!(format!("{:03?}", list), "[1024, 007]");
|
||||
assert_eq!(format!("{:03?}", map), r#"{"bar": 1024, "baz": 007}"#);
|
||||
assert_eq!(format!("{:03?}", set), "{007, 1024}");
|
||||
assert_eq!(format!("{:#03?}", struct_), "
|
||||
Foo {
|
||||
bar: 1024,
|
||||
baz: 007
|
||||
}
|
||||
".trim());
|
||||
assert_eq!(format!("{:#03?}", tuple), "
|
||||
(
|
||||
1024,
|
||||
007
|
||||
)
|
||||
".trim());
|
||||
assert_eq!(format!("{:#03?}", list), "
|
||||
[
|
||||
1024,
|
||||
007
|
||||
]
|
||||
".trim());
|
||||
assert_eq!(format!("{:#03?}", map), r#"
|
||||
{
|
||||
"bar": 1024,
|
||||
"baz": 007
|
||||
}
|
||||
"#.trim());
|
||||
assert_eq!(format!("{:#03?}", set), "
|
||||
{
|
||||
007,
|
||||
1024
|
||||
}
|
||||
".trim());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue