Skip to content

Commit e98ea52

Browse files
committed
add key and value methods to DebugMap
1 parent d3e2cec commit e98ea52

File tree

4 files changed

+236
-25
lines changed

4 files changed

+236
-25
lines changed
Lines changed: 9 additions & 0 deletions
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

Lines changed: 141 additions & 17 deletions
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,121 @@ 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+
/// use std::fmt;
754+
///
755+
/// struct Foo(Vec<(String, i32)>);
756+
///
757+
/// impl fmt::Debug for Foo {
758+
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
759+
/// fmt.debug_map()
760+
/// .key(&"whole").value(&self.0) // We add the "whole" entry.
761+
/// .finish()
762+
/// }
763+
/// }
764+
///
765+
/// assert_eq!(
766+
/// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
767+
/// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
768+
/// );
769+
/// ```
770+
#[unstable(feature = "debug_map_key_value",
771+
reason = "recently added",
772+
issue = "62482")]
773+
pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
774+
assert!(!self.has_key, "attempted to begin a new map entry \
775+
without completing the previous one");
776+
715777
self.result = self.result.and_then(|_| {
716778
if self.is_pretty() {
717779
if !self.has_fields {
718780
self.fmt.write_str("\n")?;
719781
}
720782
let mut slot = None;
721-
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
783+
self.state = Default::default();
784+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
722785
key.fmt(&mut writer)?;
723786
writer.write_str(": ")?;
724-
value.fmt(&mut writer)?;
725-
writer.write_str(",\n")
726787
} else {
727788
if self.has_fields {
728789
self.fmt.write_str(", ")?
729790
}
730791
key.fmt(self.fmt)?;
731792
self.fmt.write_str(": ")?;
732-
value.fmt(self.fmt)
733793
}
794+
795+
self.has_key = true;
796+
Ok(())
797+
});
798+
799+
self
800+
}
801+
802+
/// Adds the value part of a new entry to the map output.
803+
///
804+
/// This method, together with `key`, is an alternative to `entry` that
805+
/// can be used when the complete entry isn't known upfront. Prefer the `entry`
806+
/// method when it's possible to use.
807+
///
808+
/// # Panics
809+
///
810+
/// `key` must be called before `value` and each call to `key` must be followed
811+
/// by a corresponding call to `value`. Otherwise this method will panic.
812+
///
813+
/// # Examples
814+
///
815+
/// ```
816+
/// use std::fmt;
817+
///
818+
/// struct Foo(Vec<(String, i32)>);
819+
///
820+
/// impl fmt::Debug for Foo {
821+
/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
822+
/// fmt.debug_map()
823+
/// .key(&"whole").value(&self.0) // We add the "whole" entry.
824+
/// .finish()
825+
/// }
826+
/// }
827+
///
828+
/// assert_eq!(
829+
/// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
830+
/// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
831+
/// );
832+
/// ```
833+
#[unstable(feature = "debug_map_key_value",
834+
reason = "recently added",
835+
issue = "62482")]
836+
pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
837+
assert!(self.has_key, "attempted to format a map value before its key");
838+
839+
self.result = self.result.and_then(|_| {
840+
if self.is_pretty() {
841+
let mut slot = None;
842+
let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
843+
value.fmt(&mut writer)?;
844+
writer.write_str(",\n")?;
845+
} else {
846+
value.fmt(self.fmt)?;
847+
}
848+
849+
self.has_key = false;
850+
Ok(())
734851
});
735852

736853
self.has_fields = true;
@@ -775,6 +892,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
775892

776893
/// Finishes output and returns any error encountered.
777894
///
895+
/// # Panics
896+
///
897+
/// `key` must be called before `value` and each call to `key` must be followed
898+
/// by a corresponding call to `value`. Otherwise this method will panic.
899+
///
778900
/// # Examples
779901
///
780902
/// ```
@@ -797,6 +919,8 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
797919
/// ```
798920
#[stable(feature = "debug_builders", since = "1.2.0")]
799921
pub fn finish(&mut self) -> fmt::Result {
922+
assert!(!self.has_key, "attempted to finish a map with a partial entry");
923+
800924
self.result.and_then(|_| self.fmt.write_str("}"))
801925
}
802926

0 commit comments

Comments
 (0)