diff --git a/src/doc/unstable-book/src/library-features/debug-map-key-value.md b/src/doc/unstable-book/src/library-features/debug-map-key-value.md
new file mode 100644
index 0000000000000..ae839bf2ac32b
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/debug-map-key-value.md
@@ -0,0 +1,9 @@
+# `debug_map_key_value`
+
+The tracking issue for this feature is: [#62482]
+
+[#62482]: https://github.com/rust-lang/rust/issues/62482
+
+------------------------
+
+Add the methods `key` and `value` to `DebugMap` so that an entry can be formatted across multiple calls without additional buffering.
diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs
index df86da5fc3906..cb4e32622ff1f 100644
--- a/src/libcore/fmt/builders.rs
+++ b/src/libcore/fmt/builders.rs
@@ -1,37 +1,50 @@
 use crate::fmt;
 
-struct PadAdapter<'a> {
-    buf: &'a mut (dyn fmt::Write + 'a),
+struct PadAdapter<'buf, 'state> {
+    buf: &'buf mut (dyn fmt::Write + 'buf),
+    state: &'state mut PadAdapterState,
+}
+
+struct PadAdapterState {
     on_newline: bool,
 }
 
-impl<'a> PadAdapter<'a> {
-    fn wrap<'b, 'c: 'a+'b>(fmt: &'c mut fmt::Formatter<'_>, slot: &'b mut Option<Self>)
-                        -> fmt::Formatter<'b> {
+impl Default for PadAdapterState {
+    fn default() -> Self {
+        PadAdapterState {
+            on_newline: true,
+        }
+    }
+}
+
+impl<'buf, 'state> PadAdapter<'buf, 'state> {
+    fn wrap<'slot, 'fmt: 'buf+'slot>(fmt: &'fmt mut fmt::Formatter<'_>,
+                                     slot: &'slot mut Option<Self>,
+                                     state: &'state mut PadAdapterState) -> fmt::Formatter<'slot> {
         fmt.wrap_buf(move |buf| {
             *slot = Some(PadAdapter {
                 buf,
-                on_newline: true,
+                state,
             });
             slot.as_mut().unwrap()
         })
     }
 }
 
-impl fmt::Write for PadAdapter<'_> {
+impl fmt::Write for PadAdapter<'_, '_> {
     fn write_str(&mut self, mut s: &str) -> fmt::Result {
         while !s.is_empty() {
-            if self.on_newline {
+            if self.state.on_newline {
                 self.buf.write_str("    ")?;
             }
 
             let split = match s.find('\n') {
                 Some(pos) => {
-                    self.on_newline = true;
+                    self.state.on_newline = true;
                     pos + 1
                 }
                 None => {
-                    self.on_newline = false;
+                    self.state.on_newline = false;
                     s.len()
                 }
             };
@@ -133,7 +146,8 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> {
                     self.fmt.write_str(" {\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                let mut state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
                 writer.write_str(name)?;
                 writer.write_str(": ")?;
                 value.fmt(&mut writer)?;
@@ -279,7 +293,8 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> {
                     self.fmt.write_str("(\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                let mut state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
                 value.fmt(&mut writer)?;
                 writer.write_str(",\n")
             } else {
@@ -349,7 +364,8 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> {
                     self.fmt.write_str("\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                let mut state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state);
                 entry.fmt(&mut writer)?;
                 writer.write_str(",\n")
             } else {
@@ -676,6 +692,9 @@ pub struct DebugMap<'a, 'b: 'a> {
     fmt: &'a mut fmt::Formatter<'b>,
     result: fmt::Result,
     has_fields: bool,
+    has_key: bool,
+    // The state of newlines is tracked between keys and values
+    state: PadAdapterState,
 }
 
 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
         fmt,
         result,
         has_fields: false,
+        has_key: false,
+        state: Default::default(),
     }
 }
 
@@ -712,25 +733,123 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
+        self.key(key).value(value)
+    }
+
+    /// Adds the key part of a new entry to the map output.
+    ///
+    /// This method, together with `value`, is an alternative to `entry` that
+    /// can be used when the complete entry isn't known upfront. Prefer the `entry`
+    /// method when it's possible to use.
+    ///
+    /// # Panics
+    ///
+    /// `key` must be called before `value` and each call to `key` must be followed
+    /// by a corresponding call to `value`. Otherwise this method will panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(debug_map_key_value)]
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<(String, i32)>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         fmt.debug_map()
+    ///            .key(&"whole").value(&self.0) // We add the "whole" entry.
+    ///            .finish()
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
+    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_map_key_value",
+               reason = "recently added",
+               issue = "62482")]
+    pub fn key(&mut self, key: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
+        assert!(!self.has_key, "attempted to begin a new map entry \
+                                without completing the previous one");
+
         self.result = self.result.and_then(|_| {
             if self.is_pretty() {
                 if !self.has_fields {
                     self.fmt.write_str("\n")?;
                 }
                 let mut slot = None;
-                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot);
+                self.state = Default::default();
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
                 key.fmt(&mut writer)?;
                 writer.write_str(": ")?;
-                value.fmt(&mut writer)?;
-                writer.write_str(",\n")
             } else {
                 if self.has_fields {
                     self.fmt.write_str(", ")?
                 }
                 key.fmt(self.fmt)?;
                 self.fmt.write_str(": ")?;
-                value.fmt(self.fmt)
             }
+
+            self.has_key = true;
+            Ok(())
+        });
+
+        self
+    }
+
+    /// Adds the value part of a new entry to the map output.
+    ///
+    /// This method, together with `key`, is an alternative to `entry` that
+    /// can be used when the complete entry isn't known upfront. Prefer the `entry`
+    /// method when it's possible to use.
+    ///
+    /// # Panics
+    ///
+    /// `key` must be called before `value` and each call to `key` must be followed
+    /// by a corresponding call to `value`. Otherwise this method will panic.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// # #![feature(debug_map_key_value)]
+    /// use std::fmt;
+    ///
+    /// struct Foo(Vec<(String, i32)>);
+    ///
+    /// impl fmt::Debug for Foo {
+    ///     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+    ///         fmt.debug_map()
+    ///            .key(&"whole").value(&self.0) // We add the "whole" entry.
+    ///            .finish()
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(
+    ///     format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])),
+    ///     "{\"whole\": [(\"A\", 10), (\"B\", 11)]}",
+    /// );
+    /// ```
+    #[unstable(feature = "debug_map_key_value",
+               reason = "recently added",
+               issue = "62482")]
+    pub fn value(&mut self, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> {
+        assert!(self.has_key, "attempted to format a map value before its key");
+
+        self.result = self.result.and_then(|_| {
+            if self.is_pretty() {
+                let mut slot = None;
+                let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut self.state);
+                value.fmt(&mut writer)?;
+                writer.write_str(",\n")?;
+            } else {
+                value.fmt(self.fmt)?;
+            }
+
+            self.has_key = false;
+            Ok(())
         });
 
         self.has_fields = true;
@@ -775,6 +894,11 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
 
     /// Finishes output and returns any error encountered.
     ///
+    /// # Panics
+    ///
+    /// `key` must be called before `value` and each call to `key` must be followed
+    /// by a corresponding call to `value`. Otherwise this method will panic.
+    ///
     /// # Examples
     ///
     /// ```
@@ -797,6 +921,8 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> {
     /// ```
     #[stable(feature = "debug_builders", since = "1.2.0")]
     pub fn finish(&mut self) -> fmt::Result {
+        assert!(!self.has_key, "attempted to finish a map with a partial entry");
+
         self.result.and_then(|_| self.fmt.write_str("}"))
     }
 
diff --git a/src/libcore/tests/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs
index 62fe09c5eb32c..200659b91bb4e 100644
--- a/src/libcore/tests/fmt/builders.rs
+++ b/src/libcore/tests/fmt/builders.rs
@@ -211,9 +211,9 @@ mod debug_map {
 
     #[test]
     fn test_single() {
-        struct Foo;
+        struct Entry;
 
-        impl fmt::Debug for Foo {
+        impl fmt::Debug for Entry {
             fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 fmt.debug_map()
                     .entry(&"bar", &true)
@@ -221,19 +221,32 @@ mod debug_map {
             }
         }
 
-        assert_eq!("{\"bar\": true}", format!("{:?}", Foo));
+        struct KeyValue;
+
+        impl fmt::Debug for KeyValue {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar").value(&true)
+                    .finish()
+            }
+        }
+
+        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
+        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+
+        assert_eq!("{\"bar\": true}", format!("{:?}", Entry));
         assert_eq!(
 "{
     \"bar\": true,
 }",
-                   format!("{:#?}", Foo));
+                   format!("{:#?}", Entry));
     }
 
     #[test]
     fn test_multiple() {
-        struct Foo;
+        struct Entry;
 
-        impl fmt::Debug for Foo {
+        impl fmt::Debug for Entry {
             fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
                 fmt.debug_map()
                     .entry(&"bar", &true)
@@ -242,13 +255,27 @@ mod debug_map {
             }
         }
 
-        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Foo));
+        struct KeyValue;
+
+        impl fmt::Debug for KeyValue {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar").value(&true)
+                    .key(&10).value(&format_args!("{}/{}", 10, 20))
+                    .finish()
+            }
+        }
+
+        assert_eq!(format!("{:?}", Entry), format!("{:?}", KeyValue));
+        assert_eq!(format!("{:#?}", Entry), format!("{:#?}", KeyValue));
+
+        assert_eq!("{\"bar\": true, 10: 10/20}", format!("{:?}", Entry));
         assert_eq!(
 "{
     \"bar\": true,
     10: 10/20,
 }",
-                   format!("{:#?}", Foo));
+                   format!("{:#?}", Entry));
     }
 
     #[test]
@@ -291,6 +318,56 @@ mod debug_map {
 }",
                    format!("{:#?}", Bar));
     }
+
+    #[test]
+    #[should_panic]
+    fn test_invalid_key_when_entry_is_incomplete() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar")
+                    .key(&"invalid")
+                    .finish()
+            }
+        }
+
+        format!("{:?}", Foo);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_invalid_finish_incomplete_entry() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .key(&"bar")
+                    .finish()
+            }
+        }
+
+        format!("{:?}", Foo);
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_invalid_value_before_key() {
+        struct Foo;
+
+        impl fmt::Debug for Foo {
+            fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                fmt.debug_map()
+                    .value(&"invalid")
+                    .key(&"bar")
+                    .finish()
+            }
+        }
+
+        format!("{:?}", Foo);
+    }
 }
 
 mod debug_set {
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index bf072a9243b51..4b48d1225902b 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -3,6 +3,7 @@
 #![feature(cell_update)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
+#![feature(debug_map_key_value)]
 #![feature(dec2flt)]
 #![feature(euclidean_division)]
 #![feature(exact_size_is_empty)]