Skip to content

Commit 8cacf50

Browse files
committed
Auto merge of #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 ecbc222 + 73124df commit 8cacf50

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

src/libcore/fmt/builders.rs

+56
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,62 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
159159
self
160160
}
161161

162+
/// Marks the struct as non-exhaustive, indicating to the reader that there are some other
163+
/// fields that are not shown in the debug representation.
164+
///
165+
/// # Examples
166+
///
167+
/// ```
168+
/// # #![feature(debug_non_exhaustive)]
169+
/// use std::fmt;
170+
///
171+
/// struct Bar {
172+
/// bar: i32,
173+
/// hidden: f32,
174+
/// }
175+
///
176+
/// impl fmt::Debug for Bar {
177+
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
178+
/// fmt.debug_struct("Bar")
179+
/// .field("bar", &self.bar)
180+
/// .finish_non_exhaustive() // Show that some other field(s) exist.
181+
/// }
182+
/// }
183+
///
184+
/// assert_eq!(
185+
/// format!("{:?}", Bar { bar: 10, hidden: 1.0 }),
186+
/// "Bar { bar: 10, .. }",
187+
/// );
188+
/// ```
189+
#[unstable(feature = "debug_non_exhaustive", issue = "67364")]
190+
pub fn finish_non_exhaustive(&mut self) -> fmt::Result {
191+
self.result = self.result.and_then(|_| {
192+
// Draw non-exhaustive dots (`..`), and open brace if necessary (no fields).
193+
if self.is_pretty() {
194+
if !self.has_fields {
195+
self.fmt.write_str(" {\n")?;
196+
}
197+
let mut slot = None;
198+
let mut state = Default::default();
199+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
200+
writer.write_str("..\n")?;
201+
} else {
202+
if self.has_fields {
203+
self.fmt.write_str(", ..")?;
204+
} else {
205+
self.fmt.write_str(" { ..")?;
206+
}
207+
}
208+
if self.is_pretty() {
209+
self.fmt.write_str("}")?
210+
} else {
211+
self.fmt.write_str(" }")?;
212+
}
213+
Ok(())
214+
});
215+
self.result
216+
}
217+
162218
/// Finishes output and returns any error encountered.
163219
///
164220
/// # Examples

src/libcore/tests/fmt/builders.rs

+85
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,91 @@ mod debug_struct {
8989
baz: 10/20,
9090
},
9191
hello: \"world\",
92+
}",
93+
format!("{:#?}", Bar)
94+
);
95+
}
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").finish_non_exhaustive()
104+
}
105+
}
106+
107+
assert_eq!("Foo { .. }", format!("{:?}", Foo));
108+
assert_eq!(
109+
"Foo {
110+
..
111+
}",
112+
format!("{:#?}", Foo)
113+
);
114+
}
115+
116+
#[test]
117+
fn test_multiple_and_non_exhaustive() {
118+
struct Foo;
119+
120+
impl fmt::Debug for Foo {
121+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
122+
fmt.debug_struct("Foo")
123+
.field("bar", &true)
124+
.field("baz", &format_args!("{}/{}", 10, 20))
125+
.finish_non_exhaustive()
126+
}
127+
}
128+
129+
assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo));
130+
assert_eq!(
131+
"Foo {
132+
bar: true,
133+
baz: 10/20,
134+
..
135+
}",
136+
format!("{:#?}", Foo)
137+
);
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!(
165+
"Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }",
166+
format!("{:?}", Bar)
167+
);
168+
assert_eq!(
169+
"Bar {
170+
foo: Foo {
171+
bar: true,
172+
baz: 10/20,
173+
..
174+
},
175+
hello: \"world\",
176+
..
92177
}",
93178
format!("{:#?}", Bar)
94179
);

src/libcore/tests/lib.rs

+1
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)