Update debug helpers and add list builder

The collections debug helpers no longer prefix output with the
collection name, in line with the current conventions for Debug
implementations. Implementations that want to preserve the current
behavior can simply add a `try!(write!(fmt, "TypeName "));` at the
beginning of the `fmt` method.

[breaking-change]
This commit is contained in:
Steven Fackler 2015-03-26 22:42:29 -07:00
parent 3e7385aae9
commit 4037f2a368
10 changed files with 277 additions and 131 deletions

View File

@ -904,14 +904,11 @@ fn cmp(&self, other: &BTreeMap<K, V>) -> Ordering {
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
for (i, (k, v)) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
try!(write!(f, "{:?}: {:?}", *k, *v));
let mut builder = f.debug_map();
for (k, v) in self {
builder = builder.entry(k, v);
}
write!(f, "}}")
builder.finish()
}
}

View File

@ -628,14 +628,11 @@ fn bitor(self, rhs: &BTreeSet<T>) -> BTreeSet<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Debug> Debug for BTreeSet<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
for (i, x) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
try!(write!(f, "{:?}", *x));
let mut builder = f.debug_set();
for x in self {
builder = builder.entry(x);
}
write!(f, "}}")
builder.finish()
}
}

View File

@ -40,6 +40,7 @@
#![feature(str_char)]
#![feature(convert)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
#![cfg_attr(test, allow(deprecated))] // rand

View File

@ -927,14 +927,11 @@ fn clone(&self) -> LinkedList<A> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: fmt::Debug> fmt::Debug for LinkedList<A> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "["));
for (i, e) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
try!(write!(f, "{:?}", *e));
let mut builder = f.debug_list();
for e in self {
builder = builder.entry(e);
}
write!(f, "]")
builder.finish()
}
}

View File

@ -177,22 +177,54 @@ fn is_pretty(&self) -> bool {
}
}
/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_set` method.
#[must_use]
pub struct DebugSet<'a, 'b: 'a> {
struct DebugInner<'a, 'b: 'a> {
fmt: &'a mut fmt::Formatter<'b>,
result: fmt::Result,
has_fields: bool,
}
pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugSet<'a, 'b> {
let result = write!(fmt, "{} {{", name);
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 { "," } else { "" };
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
} else {
let prefix = if self.has_fields { ", " } else { "" };
write!(self.fmt, "{}{:?}", prefix, entry)
}
});
self.has_fields = true;
}
pub fn finish(&mut self) {
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
}
fn is_pretty(&self) -> bool {
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
}
}
/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_set` method.
#[must_use]
pub struct DebugSet<'a, 'b: 'a> {
inner: DebugInner<'a, 'b>,
}
pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> {
let result = write!(fmt, "{{");
DebugSet {
fmt: fmt,
result: result,
has_fields: false,
inner: DebugInner {
fmt: fmt,
result: result,
has_fields: false,
}
}
}
@ -200,41 +232,52 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> {
/// Adds a new entry to the set output.
#[unstable(feature = "debug_builders", reason = "method was just created")]
pub fn entry(mut self, entry: &fmt::Debug) -> DebugSet<'a, 'b> {
self.result = self.result.and_then(|_| {
let prefix = if self.has_fields {
","
} else {
""
};
if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt);
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
} else {
write!(self.fmt, "{} {:?}", prefix, entry)
}
});
self.has_fields = true;
self.inner.entry(entry);
self
}
/// Consumes the `DebugSet`, finishing output and returning any error
/// encountered.
#[unstable(feature = "debug_builders", reason = "method was just created")]
pub fn finish(self) -> fmt::Result {
self.result.and_then(|_| {
let end = match (self.has_fields, self.is_pretty()) {
(false, _) => "}",
(true, false) => " }",
(true, true) => "\n}",
};
self.fmt.write_str(end)
})
pub fn finish(mut self) -> fmt::Result {
self.inner.finish();
self.inner.result.and_then(|_| self.inner.fmt.write_str("}"))
}
}
/// A struct to help with `fmt::Debug` implementations.
///
/// Constructed by the `Formatter::debug_list` method.
#[must_use]
pub struct DebugList<'a, 'b: 'a> {
inner: DebugInner<'a, 'b>,
}
pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> {
let result = write!(fmt, "[");
DebugList {
inner: DebugInner {
fmt: fmt,
result: result,
has_fields: false,
}
}
}
impl<'a, 'b: 'a> DebugList<'a, 'b> {
/// Adds a new entry to the set output.
#[unstable(feature = "debug_builders", reason = "method was just created")]
pub fn entry(mut self, entry: &fmt::Debug) -> DebugList<'a, 'b> {
self.inner.entry(entry);
self
}
fn is_pretty(&self) -> bool {
self.fmt.flags() & (1 << (FlagV1::Alternate as usize)) != 0
/// Consumes the `DebugSet`, finishing output and returning any error
/// encountered.
#[unstable(feature = "debug_builders", reason = "method was just created")]
pub fn finish(mut self) -> fmt::Result {
self.inner.finish();
self.inner.result.and_then(|_| self.inner.fmt.write_str("]"))
}
}
@ -248,8 +291,8 @@ pub struct DebugMap<'a, 'b: 'a> {
has_fields: bool,
}
pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> DebugMap<'a, 'b> {
let result = write!(fmt, "{} {{", name);
pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
let result = write!(fmt, "{{");
DebugMap {
fmt: fmt,
result: result,
@ -262,22 +305,17 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
#[unstable(feature = "debug_builders", reason = "method was just created")]
pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b> {
self.result = self.result.and_then(|_| {
let prefix = if self.has_fields {
","
} else {
""
};
if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt);
let prefix = if self.has_fields { "," } else { "" };
fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
} else {
write!(self.fmt, "{} {:?}: {:?}", prefix, key, value)
let prefix = if self.has_fields { ", " } else { "" };
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
}
});
self.has_fields = true;
self
}
@ -285,14 +323,8 @@ pub fn entry(mut self, key: &fmt::Debug, value: &fmt::Debug) -> DebugMap<'a, 'b>
/// encountered.
#[unstable(feature = "debug_builders", reason = "method was just created")]
pub fn finish(self) -> fmt::Result {
self.result.and_then(|_| {
let end = match (self.has_fields, self.is_pretty()) {
(false, _) => "}",
(true, false) => " }",
(true, true) => "\n}",
};
self.fmt.write_str(end)
})
let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
}
fn is_pretty(&self) -> bool {

View File

@ -32,7 +32,7 @@
pub use self::num::Radix;
pub use self::num::RadixFmt;
pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugMap};
pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugList, DebugMap};
mod num;
mod float;
@ -644,7 +644,7 @@ pub fn precision(&self) -> Option<usize> { self.precision }
/// // prints "Foo { bar: 10, baz: "Hello World" }"
/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() });
/// ```
#[unstable(feature = "core", reason = "method was just created")]
#[unstable(feature = "debug_builders", reason = "method was just created")]
#[inline]
pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> {
builders::debug_struct_new(self, name)
@ -673,12 +673,42 @@ pub fn debug_struct<'b>(&'b mut self, name: &str) -> DebugStruct<'b, 'a> {
/// // prints "Foo(10, "Hello World")"
/// println!("{:?}", Foo(10, "Hello World".to_string()));
/// ```
#[unstable(feature = "core", reason = "method was just created")]
#[unstable(feature = "debug_builders", reason = "method was just created")]
#[inline]
pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> {
builders::debug_tuple_new(self, name)
}
/// Creates a `DebugList` builder designed to assist with creation of
/// `fmt::Debug` implementations for list-like structures.
///
/// # Examples
///
/// ```rust
/// # #![feature(debug_builders, core)]
/// use std::fmt;
///
/// struct Foo(Vec<i32>);
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// let mut builder = fmt.debug_list();
/// for i in &self.0 {
/// builder = builder.entry(i);
/// }
/// builder.finish()
/// }
/// }
///
/// // prints "Foo { 10, 11 }"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
#[unstable(feature = "debug_builders", reason = "method was just created")]
#[inline]
pub fn debug_list<'b>(&'b mut self) -> DebugList<'b, 'a> {
builders::debug_list_new(self)
}
/// Creates a `DebugSet` builder designed to assist with creation of
/// `fmt::Debug` implementations for set-like structures.
///
@ -692,7 +722,7 @@ pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> {
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// let mut builder = fmt.debug_set("Foo");
/// let mut builder = fmt.debug_set();
/// for i in &self.0 {
/// builder = builder.entry(i);
/// }
@ -703,10 +733,10 @@ pub fn debug_tuple<'b>(&'b mut self, name: &str) -> DebugTuple<'b, 'a> {
/// // prints "Foo { 10, 11 }"
/// println!("{:?}", Foo(vec![10, 11]));
/// ```
#[unstable(feature = "core", reason = "method was just created")]
#[unstable(feature = "debug_builders", reason = "method was just created")]
#[inline]
pub fn debug_set<'b>(&'b mut self, name: &str) -> DebugSet<'b, 'a> {
builders::debug_set_new(self, name)
pub fn debug_set<'b>(&'b mut self) -> DebugSet<'b, 'a> {
builders::debug_set_new(self)
}
/// Creates a `DebugMap` builder designed to assist with creation of
@ -722,7 +752,7 @@ pub fn debug_set<'b>(&'b mut self, name: &str) -> DebugSet<'b, 'a> {
///
/// impl fmt::Debug for Foo {
/// fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
/// let mut builder = fmt.debug_map("Foo");
/// let mut builder = fmt.debug_map();
/// for &(ref key, ref value) in &self.0 {
/// builder = builder.entry(key, value);
/// }
@ -733,10 +763,10 @@ pub fn debug_set<'b>(&'b mut self, name: &str) -> DebugSet<'b, 'a> {
/// // prints "Foo { "A": 10, "B": 11 }"
/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)]));
/// ```
#[unstable(feature = "core", reason = "method was just created")]
#[unstable(feature = "debug_builders", reason = "method was just created")]
#[inline]
pub fn debug_map<'b>(&'b mut self, name: &str) -> DebugMap<'b, 'a> {
builders::debug_map_new(self, name)
pub fn debug_map<'b>(&'b mut self) -> DebugMap<'b, 'a> {
builders::debug_map_new(self)
}
}

View File

@ -211,12 +211,12 @@ fn test_empty() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_map("Foo").finish()
fmt.debug_map().finish()
}
}
assert_eq!("Foo {}", format!("{:?}", Foo));
assert_eq!("Foo {}", format!("{:#?}", Foo));
assert_eq!("{}", format!("{:?}", Foo));
assert_eq!("{}", format!("{:#?}", Foo));
}
#[test]
@ -225,15 +225,15 @@ fn test_single() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_map("Foo")
fmt.debug_map()
.entry(&"bar", &true)
.finish()
}
}
assert_eq!("Foo { \"bar\": true }", format!("{:?}", Foo));
assert_eq!("{\"bar\": true}", format!("{:?}", Foo));
assert_eq!(
"Foo {
"{
\"bar\": true
}",
format!("{:#?}", Foo));
@ -245,16 +245,16 @@ fn test_multiple() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_map("Foo")
fmt.debug_map()
.entry(&"bar", &true)
.entry(&10i32, &format_args!("{}/{}", 10i32, 20i32))
.finish()
}
}
assert_eq!("Foo { \"bar\": true, 10: 10/20 }", format!("{:?}", Foo));
assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Foo));
assert_eq!(
"Foo {
"{
\"bar\": true,
10: 10/20
}",
@ -267,7 +267,7 @@ fn test_nested() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_map("Foo")
fmt.debug_map()
.entry(&"bar", &true)
.entry(&10i32, &format_args!("{}/{}", 10i32, 20i32))
.finish()
@ -278,23 +278,23 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Debug for Bar {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_map("Bar")
fmt.debug_map()
.entry(&"foo", &Foo)
.entry(&Foo, &"world")
.finish()
}
}
assert_eq!("Bar { \"foo\": Foo { \"bar\": true, 10: 10/20 }, \
Foo { \"bar\": true, 10: 10/20 }: \"world\" }",
assert_eq!("{\"foo\": {\"bar\": true, 10: 10/20}, \
{\"bar\": true, 10: 10/20}: \"world\"}",
format!("{:?}", Bar));
assert_eq!(
"Bar {
\"foo\": Foo {
"{
\"foo\": {
\"bar\": true,
10: 10/20
},
Foo {
{
\"bar\": true,
10: 10/20
}: \"world\"
@ -312,12 +312,12 @@ fn test_empty() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_set("Foo").finish()
fmt.debug_set().finish()
}
}
assert_eq!("Foo {}", format!("{:?}", Foo));
assert_eq!("Foo {}", format!("{:#?}", Foo));
assert_eq!("{}", format!("{:?}", Foo));
assert_eq!("{}", format!("{:#?}", Foo));
}
#[test]
@ -326,15 +326,15 @@ fn test_single() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_set("Foo")
fmt.debug_set()
.entry(&true)
.finish()
}
}
assert_eq!("Foo { true }", format!("{:?}", Foo));
assert_eq!("{true}", format!("{:?}", Foo));
assert_eq!(
"Foo {
"{
true
}",
format!("{:#?}", Foo));
@ -346,16 +346,16 @@ fn test_multiple() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_set("Foo")
fmt.debug_set()
.entry(&true)
.entry(&format_args!("{}/{}", 10i32, 20i32))
.finish()
}
}
assert_eq!("Foo { true, 10/20 }", format!("{:?}", Foo));
assert_eq!("{true, 10/20}", format!("{:?}", Foo));
assert_eq!(
"Foo {
"{
true,
10/20
}",
@ -368,7 +368,7 @@ fn test_nested() {
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_set("Foo")
fmt.debug_set()
.entry(&true)
.entry(&format_args!("{}/{}", 10i32, 20i32))
.finish()
@ -379,18 +379,18 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Debug for Bar {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_set("Bar")
fmt.debug_set()
.entry(&Foo)
.entry(&"world")
.finish()
}
}
assert_eq!("Bar { Foo { true, 10/20 }, \"world\" }",
assert_eq!("{{true, 10/20}, \"world\"}",
format!("{:?}", Bar));
assert_eq!(
"Bar {
Foo {
"{
{
true,
10/20
},
@ -399,3 +399,100 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
format!("{:#?}", Bar));
}
}
mod debug_list {
use std::fmt;
#[test]
fn test_empty() {
struct Foo;
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_list().finish()
}
}
assert_eq!("[]", format!("{:?}", Foo));
assert_eq!("[]", format!("{:#?}", Foo));
}
#[test]
fn test_single() {
struct Foo;
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_list()
.entry(&true)
.finish()
}
}
assert_eq!("[true]", format!("{:?}", Foo));
assert_eq!(
"[
true
]",
format!("{:#?}", Foo));
}
#[test]
fn test_multiple() {
struct Foo;
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_list()
.entry(&true)
.entry(&format_args!("{}/{}", 10i32, 20i32))
.finish()
}
}
assert_eq!("[true, 10/20]", format!("{:?}", Foo));
assert_eq!(
"[
true,
10/20
]",
format!("{:#?}", Foo));
}
#[test]
fn test_nested() {
struct Foo;
impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_list()
.entry(&true)
.entry(&format_args!("{}/{}", 10i32, 20i32))
.finish()
}
}
struct Bar;
impl fmt::Debug for Bar {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_list()
.entry(&Foo)
.entry(&"world")
.finish()
}
}
assert_eq!("[[true, 10/20], \"world\"]",
format!("{:?}", Bar));
assert_eq!(
"[
[
true,
10/20
],
\"world\"
]",
format!("{:#?}", Bar));
}
}

View File

@ -1226,14 +1226,11 @@ impl<K, V, S> Debug for HashMap<K, V, S>
where K: Eq + Hash + Debug, V: Debug, S: HashState
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
for (i, (k, v)) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
try!(write!(f, "{:?}: {:?}", *k, *v));
let mut builder = f.debug_map();
for (k, v) in self.iter() {
builder = builder.entry(k, v);
}
write!(f, "}}")
builder.finish()
}
}

View File

@ -614,14 +614,11 @@ impl<T, S> fmt::Debug for HashSet<T, S>
S: HashState
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, "{{"));
for (i, x) in self.iter().enumerate() {
if i != 0 { try!(write!(f, ", ")); }
try!(write!(f, "{:?}", *x));
let mut builder = f.debug_set();
for x in self {
builder = builder.entry(x);
}
write!(f, "}}")
builder.finish()
}
}

View File

@ -128,6 +128,7 @@
#![feature(into_cow)]
#![feature(slice_patterns)]
#![feature(std_misc)]
#![feature(debug_builders)]
#![cfg_attr(test, feature(test, rustc_private, std_misc))]
// Don't link to std. We are std.