Skip to content

Commit 0d64c51

Browse files
Rollup merge of rust-lang#66716 - derekdreery:debug_non_exhaustive, r=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, .. }", ); ```
2 parents 19bd934 + 985127c commit 0d64c51

File tree

3 files changed

+147
-6
lines changed

3 files changed

+147
-6
lines changed

src/libcore/fmt/builders.rs

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,62 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
165165
self
166166
}
167167

168+
/// Marks the struct as non-exhaustive, indicating to the reader that there are some other
169+
/// fields that are not shown in the debug representation.
170+
///
171+
/// # Examples
172+
///
173+
/// ```
174+
/// # #![feature(debug_non_exhaustive)]
175+
/// use std::fmt;
176+
///
177+
/// struct Bar {
178+
/// bar: i32,
179+
/// hidden: f32,
180+
/// }
181+
///
182+
/// impl fmt::Debug for Bar {
183+
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
184+
/// fmt.debug_struct("Bar")
185+
/// .field("bar", &self.bar)
186+
/// .finish_non_exhaustive() // Show that some other field(s) exist.
187+
/// }
188+
/// }
189+
///
190+
/// assert_eq!(
191+
/// format!("{:?}", Bar { bar: 10, hidden: 1.0 }),
192+
/// "Bar { bar: 10, .. }",
193+
/// );
194+
/// ```
195+
#[unstable(feature = "debug_non_exhaustive", issue = "67364")]
196+
pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
197+
self.result = self.result.and_then(|_| {
198+
// Draw non-exhaustive dots (`..`), and open brace if necessary (no fields).
199+
if self.is_pretty() {
200+
if !self.has_fields {
201+
self.fmt.write_str(" {\n")?;
202+
}
203+
let mut slot = None;
204+
let mut state = Default::default();
205+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
206+
writer.write_str("..\n")?;
207+
} else {
208+
if self.has_fields {
209+
self.fmt.write_str(", ..")?;
210+
} else {
211+
self.fmt.write_str(" { ..")?;
212+
}
213+
}
214+
if self.is_pretty() {
215+
self.fmt.write_str("}")?
216+
} else {
217+
self.fmt.write_str(" }")?;
218+
}
219+
Ok(())
220+
});
221+
self.result
222+
}
223+
168224
/// Finishes output and returns any error encountered.
169225
///
170226
/// # Examples
@@ -194,15 +250,16 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
194250
/// ```
195251
#[stable(feature = "debug_builders", since = "1.2.0")]
196252
pub fn finish(&mut self) -> fmt::Result {
197-
if self.has_fields {
198-
self.result = self.result.and_then(|_| {
253+
self.result = self.result.and_then(|_| {
254+
if self.has_fields {
199255
if self.is_pretty() {
200-
self.fmt.write_str("}")
256+
self.fmt.write_str("}")?
201257
} else {
202-
self.fmt.write_str(" }")
258+
self.fmt.write_str(" }")?;
203259
}
204-
});
205-
}
260+
}
261+
Ok(())
262+
});
206263
self.result
207264
}
208265

src/libcore/tests/fmt/builders.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,89 @@ mod debug_struct {
9393
}",
9494
format!("{:#?}", Bar));
9595
}
96+
97+
#[test]
98+
fn test_only_non_exhaustive() {
99+
struct Foo;
100+
101+
impl fmt::Debug for Foo {
102+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
103+
fmt.debug_struct("Foo")
104+
.finish_non_exhaustive()
105+
}
106+
}
107+
108+
109+
assert_eq!("Foo { .. }", format!("{:?}", Foo));
110+
assert_eq!(
111+
"Foo {
112+
..
113+
}",
114+
format!("{:#?}", Foo));
115+
}
116+
117+
#[test]
118+
fn test_multiple_and_non_exhaustive() {
119+
struct Foo;
120+
121+
impl fmt::Debug for Foo {
122+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
123+
fmt.debug_struct("Foo")
124+
.field("bar", &true)
125+
.field("baz", &format_args!("{}/{}", 10, 20))
126+
.finish_non_exhaustive()
127+
}
128+
}
129+
130+
assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo));
131+
assert_eq!(
132+
"Foo {
133+
bar: true,
134+
baz: 10/20,
135+
..
136+
}",
137+
format!("{:#?}", Foo));
138+
}
139+
140+
#[test]
141+
fn test_nested_non_exhaustive() {
142+
struct Foo;
143+
144+
impl fmt::Debug for Foo {
145+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
146+
fmt.debug_struct("Foo")
147+
.field("bar", &true)
148+
.field("baz", &format_args!("{}/{}", 10, 20))
149+
.finish_non_exhaustive()
150+
}
151+
}
152+
153+
struct Bar;
154+
155+
impl fmt::Debug for Bar {
156+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
157+
fmt.debug_struct("Bar")
158+
.field("foo", &Foo)
159+
.field("hello", &"world")
160+
.finish_non_exhaustive()
161+
}
162+
}
163+
164+
assert_eq!("Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
165+
format!("{:?}", Bar));
166+
assert_eq!(
167+
"Bar {
168+
foo: Foo {
169+
bar: true,
170+
baz: 10/20,
171+
..
172+
},
173+
hello: \"world\",
174+
..
175+
}",
176+
format!("{:#?}", Bar));
177+
}
178+
96179
}
97180

98181
mod debug_tuple {

src/libcore/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![feature(core_private_bignum)]
66
#![feature(core_private_diy_float)]
77
#![feature(debug_map_key_value)]
8+
#![feature(debug_non_exhaustive)]
89
#![feature(dec2flt)]
910
#![feature(exact_size_is_empty)]
1011
#![feature(fixed_size_array)]

0 commit comments

Comments
 (0)