Skip to content

Commit fb9ca03

Browse files
authored
Rollup merge of rust-lang#60458 - KodrAus:debug_map_entry, r=alexcrichton
Add key and value methods to DebugMap Implementation PR for an active (not approved) RFC: rust-lang/rfcs#2696. Add two new methods to `std::fmt::DebugMap` for writing the key and value part of a map entry separately: ```rust impl<'a, 'b: 'a> DebugMap<'a, 'b> { pub fn key(&mut self, key: &dyn Debug) -> &mut Self; pub fn value(&mut self, value: &dyn Debug) -> &mut Self; } ``` I want to do this so that I can write a `serde::Serializer` that forwards to our format builders, so that any `T: Serialize` can also be treated like a `T: Debug`.
2 parents 09ab31b + 70d630f commit fb9ca03

File tree

4 files changed

+238
-25
lines changed

4 files changed

+238
-25
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# `debug_map_key_value`
2+
3+
The tracking issue for this feature is: [#62482]
4+
5+
[#62482]: https://github.com/rust-lang/rust/issues/62482
6+
7+
------------------------
8+
9+
Add the methods `key` and `value` to `DebugMap` so that an entry can be formatted across multiple calls without additional buffering.

src/libcore/fmt/builders.rs

+143-17
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,50 @@
11
use crate::fmt;
22

3-
struct PadAdapter<'a> {
4-
buf: &'a mut (dyn fmt::Write + 'a),
3+
struct PadAdapter<'buf, 'state> {
4+
buf: &'buf mut (dyn fmt::Write + 'buf),
5+
state: &'state mut PadAdapterState,
6+
}
7+
8+
struct PadAdapterState {
59
on_newline: bool,
610
}
711

8-
impl<'a> PadAdapter<'a> {
9-
fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter<'_>, slot: &'b mut Option<Self>)
10-
-> fmt::Formatter<'b> {
12+
impl Default for PadAdapterState {
13+
fn default() -> Self {
14+
PadAdapterState {
15+
on_newline: true,
16+
}
17+
}
18+
}
19+
20+
impl<'buf, 'state> PadAdapter<'buf, 'state> {
21+
fn wrap<'slot, 'fmt: 'buf+'slot>(fmt: &'fmt mut fmt::Formatter<'_>,
22+
slot: &'slot mut Option<Self>,
23+
state: &'state mut PadAdapterState) -> fmt::Formatter<'slot> {
1124
fmt.wrap_buf(move |buf| {
1225
*slot = Some(PadAdapter {
1326
buf,
14-
on_newline: true,
27+
state,
1528
});
1629
slot.as_mut().unwrap()
1730
})
1831
}
1932
}
2033

21-
impl fmt::Write for PadAdapter<'_> {
34+
impl fmt::Write for PadAdapter<'_, '_> {
2235
fn write_str(&mut self, mut s: &str) -> fmt::Result {
2336
while !s.is_empty() {
24-
if self.on_newline {
37+
if self.state.on_newline {
2538
self.buf.write_str(" ")?;
2639
}
2740

2841
let split = match s.find('\n') {
2942
Some(pos) => {
30-
self.on_newline = true;
43+
self.state.on_newline = true;
3144
pos + 1
3245
}
3346
None => {
34-
self.on_newline = false;
47+
self.state.on_newline = false;
3548
s.len()
3649
}
3750
};
@@ -133,7 +146,8 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
133146
self.fmt.write_str(" {\n")?;
134147
}
135148
let mut slot = None;
136-
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
149+
let mut state = Default::default();
150+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
137151
writer.write_str(name)?;
138152
writer.write_str(": ")?;
139153
value.fmt(&mut writer)?;
@@ -279,7 +293,8 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
279293
self.fmt.write_str("(\n")?;
280294
}
281295
let mut slot = None;
282-
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
296+
let mut state = Default::default();
297+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
283298
value.fmt(&mut writer)?;
284299
writer.write_str(",\n")
285300
} else {
@@ -349,7 +364,8 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
349364
self.fmt.write_str("\n")?;
350365
}
351366
let mut slot = None;
352-
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
367+
let mut state = Default::default();
368+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
353369
entry.fmt(&mut writer)?;
354370
writer.write_str(",\n")
355371
} else {
@@ -676,6 +692,9 @@ pub struct DebugMap<'a, 'b: 'a> {
676692
fmt: &'a mut fmt::Formatter<'b>,
677693
result: fmt::Result,
678694
has_fields: bool,
695+
has_key: bool,
696+
// The state of newlines is tracked between keys and values
697+
state: PadAdapterState,
679698
}
680699

681700
pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> {
@@ -684,6 +703,8 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b
684703
fmt,
685704
result,
686705
has_fields: false,
706+
has_key: false,
707+
state: Default::default(),
687708
}
688709
}
689710

@@ -712,25 +733,123 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
712733
/// ```
713734
#[stable(feature = "debug_builders", since = "1.2.0")]
714735
pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
736+
self.key(key).value(value)
737+
}
738+
739+
/// Adds the key part of a new entry to the map output.
740+
///
741+
/// This method, together with `value`, is an alternative to `entry` that
742+
/// can be used when the complete entry isn't known upfront. Prefer the `entry`
743+
/// method when it's possible to use.
744+
///
745+
/// # Panics
746+
///
747+
/// `key` must be called before `value` and each call to `key` must be followed
748+
/// by a corresponding call to `value`. Otherwise this method will panic.
749+
///
750+
/// # Examples
751+
///
752+
/// ```
753+
/// # #![feature(debug_map_key_value)]
754+
/// use std::fmt;
755+
///
756+
/// struct Foo(Vec<(String, i32)>);
757+
///
758+
/// impl fmt::Debug for Foo {
759+
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
760+
/// fmt.debug_map()
761+
/// .key(&"whole").value(&self.0) // We add the "whole" entry.
762+
/// .finish()
763+
/// }
764+
/// }
765+
///
766+
/// assert_eq!(
767+
/// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
768+
/// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
769+
/// );
770+
/// ```
771+
#[unstable(feature = "debug_map_key_value",
772+
reason = "recently added",
773+
issue = "62482")]
774+
pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
775+
assert!(!self.has_key, "attempted to begin a new map entry \
776+
without completing the previous one");
777+
715778
self.result = self.result.and_then(|_| {
716779
if self.is_pretty() {
717780
if !self.has_fields {
718781
self.fmt.write_str("\n")?;
719782
}
720783
let mut slot = None;
721-
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
784+
self.state = Default::default();
785+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
722786
key.fmt(&mut writer)?;
723787
writer.write_str(": ")?;
724-
value.fmt(&mut writer)?;
725-
writer.write_str(",\n")
726788
} else {
727789
if self.has_fields {
728790
self.fmt.write_str(", ")?
729791
}
730792
key.fmt(self.fmt)?;
731793
self.fmt.write_str(": ")?;
732-
value.fmt(self.fmt)
733794
}
795+
796+
self.has_key = true;
797+
Ok(())
798+
});
799+
800+
self
801+
}
802+
803+
/// Adds the value part of a new entry to the map output.
804+
///
805+
/// This method, together with `key`, is an alternative to `entry` that
806+
/// can be used when the complete entry isn't known upfront. Prefer the `entry`
807+
/// method when it's possible to use.
808+
///
809+
/// # Panics
810+
///
811+
/// `key` must be called before `value` and each call to `key` must be followed
812+
/// by a corresponding call to `value`. Otherwise this method will panic.
813+
///
814+
/// # Examples
815+
///
816+
/// ```
817+
/// # #![feature(debug_map_key_value)]
818+
/// use std::fmt;
819+
///
820+
/// struct Foo(Vec<(String, i32)>);
821+
///
822+
/// impl fmt::Debug for Foo {
823+
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
824+
/// fmt.debug_map()
825+
/// .key(&"whole").value(&self.0) // We add the "whole" entry.
826+
/// .finish()
827+
/// }
828+
/// }
829+
///
830+
/// assert_eq!(
831+
/// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
832+
/// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
833+
/// );
834+
/// ```
835+
#[unstable(feature = "debug_map_key_value",
836+
reason = "recently added",
837+
issue = "62482")]
838+
pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
839+
assert!(self.has_key, "attempted to format a map value before its key");
840+
841+
self.result = self.result.and_then(|_| {
842+
if self.is_pretty() {
843+
let mut slot = None;
844+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
845+
value.fmt(&mut writer)?;
846+
writer.write_str(",\n")?;
847+
} else {
848+
value.fmt(self.fmt)?;
849+
}
850+
851+
self.has_key = false;
852+
Ok(())
734853
});
735854

736855
self.has_fields = true;
@@ -775,6 +894,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
775894

776895
/// Finishes output and returns any error encountered.
777896
///
897+
/// # Panics
898+
///
899+
/// `key` must be called before `value` and each call to `key` must be followed
900+
/// by a corresponding call to `value`. Otherwise this method will panic.
901+
///
778902
/// # Examples
779903
///
780904
/// ```
@@ -797,6 +921,8 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
797921
/// ```
798922
#[stable(feature = "debug_builders", since = "1.2.0")]
799923
pub fn finish(&mut self) -> fmt::Result {
924+
assert!(!self.has_key, "attempted to finish a map with a partial entry");
925+
800926
self.result.and_then(|_| self.fmt.write_str("}"))
801927
}
802928

0 commit comments

Comments
 (0)