Skip to content

Commit

Permalink
Rollup merge of rust-lang#66716 - derekdreery:debug_non_exhaustive, r…
Browse files Browse the repository at this point in the history
…=dtolnay

Implement `DebugStruct::non_exhaustive`.

This patch adds a function (finish_non_exhaustive) to add ellipsis before the closing brace when formatting using `DebugStruct`.

 ## Example

 ```rust
 #![feature(debug_non_exhaustive)]
 use std::fmt;

 struct Bar {
     bar: i32,
     hidden: f32,
 }

 impl fmt::Debug for Bar {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt.debug_struct("Bar")
            .field("bar", &self.bar)
            .non_exhaustive(true) // Show that some other field(s) exist.
            .finish()
     }
 }

 assert_eq!(
     format!("{:?}", Bar { bar: 10, hidden: 1.0 }),
     "Bar { bar: 10, .. }",
 );
 ```
  • Loading branch information
tmandry committed Dec 18, 2019
2 parents 3ed3b8b + 985127c commit 50fd06a
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 6 deletions.
69 changes: 63 additions & 6 deletions src/libcore/fmt/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,62 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
self
}

/// Marks the struct as non-exhaustive, indicating to the reader that there are some other
/// fields that are not shown in the debug representation.
///
/// # Examples
///
/// ```
/// # #![feature(debug_non_exhaustive)]
/// use std::fmt;
///
/// struct Bar {
/// bar: i32,
/// hidden: f32,
/// }
///
/// impl fmt::Debug for Bar {
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
/// fmt.debug_struct("Bar")
/// .field("bar", &self.bar)
/// .finish_non_exhaustive() // Show that some other field(s) exist.
/// }
/// }
///
/// assert_eq!(
/// format!("{:?}", Bar { bar: 10, hidden: 1.0 }),
/// "Bar { bar: 10, .. }",
/// );
/// ```
#[unstable(feature = "debug_non_exhaustive", issue = "67364")]
pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
self.result = self.result.and_then(|_| {
// Draw non-exhaustive dots (`..`), and open brace if necessary (no fields).
if self.is_pretty() {
if !self.has_fields {
self.fmt.write_str(" {\n")?;
}
let mut slot = None;
let mut state = Default::default();
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
writer.write_str("..\n")?;
} else {
if self.has_fields {
self.fmt.write_str(", ..")?;
} else {
self.fmt.write_str(" { ..")?;
}
}
if self.is_pretty() {
self.fmt.write_str("}")?
} else {
self.fmt.write_str(" }")?;
}
Ok(())
});
self.result
}

/// Finishes output and returns any error encountered.
///
/// # Examples
Expand Down Expand Up @@ -194,15 +250,16 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
/// ```
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn finish(&mut self) -> fmt::Result {
if self.has_fields {
self.result = self.result.and_then(|_| {
self.result = self.result.and_then(|_| {
if self.has_fields {
if self.is_pretty() {
self.fmt.write_str("}")
self.fmt.write_str("}")?
} else {
self.fmt.write_str(" }")
self.fmt.write_str(" }")?;
}
});
}
}
Ok(())
});
self.result
}

Expand Down
83 changes: 83 additions & 0 deletions src/libcore/tests/fmt/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,89 @@ mod debug_struct {
}",
format!("{:#?}", Bar));
}

#[test]
fn test_only_non_exhaustive() {
struct Foo;

impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Foo")
.finish_non_exhaustive()
}
}


assert_eq!("Foo { .. }", format!("{:?}", Foo));
assert_eq!(
"Foo {
..
}",
format!("{:#?}", Foo));
}

#[test]
fn test_multiple_and_non_exhaustive() {
struct Foo;

impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Foo")
.field("bar", &true)
.field("baz", &format_args!("{}/{}", 10, 20))
.finish_non_exhaustive()
}
}

assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo));
assert_eq!(
"Foo {
bar: true,
baz: 10/20,
..
}",
format!("{:#?}", Foo));
}

#[test]
fn test_nested_non_exhaustive() {
struct Foo;

impl fmt::Debug for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Foo")
.field("bar", &true)
.field("baz", &format_args!("{}/{}", 10, 20))
.finish_non_exhaustive()
}
}

struct Bar;

impl fmt::Debug for Bar {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("Bar")
.field("foo", &Foo)
.field("hello", &"world")
.finish_non_exhaustive()
}
}

assert_eq!("Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
format!("{:?}", Bar));
assert_eq!(
"Bar {
foo: Foo {
bar: true,
baz: 10/20,
..
},
hello: \"world\",
..
}",
format!("{:#?}", Bar));
}

}

mod debug_tuple {
Expand Down
1 change: 1 addition & 0 deletions src/libcore/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(debug_map_key_value)]
#![feature(debug_non_exhaustive)]
#![feature(dec2flt)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
Expand Down

0 comments on commit 50fd06a

Please sign in to comment.