about summary refs log tree commit diff
path: root/src/librustdoc/html
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html')
-rw-r--r--src/librustdoc/html/format.rs170
-rw-r--r--src/librustdoc/html/highlight.rs194
-rw-r--r--src/librustdoc/html/highlight/tests.rs31
-rw-r--r--src/librustdoc/html/layout.rs25
-rw-r--r--src/librustdoc/html/markdown.rs83
-rw-r--r--src/librustdoc/html/markdown/tests.rs16
-rw-r--r--src/librustdoc/html/render/context.rs92
-rw-r--r--src/librustdoc/html/render/mod.rs456
-rw-r--r--src/librustdoc/html/render/print_item.rs674
-rw-r--r--src/librustdoc/html/render/search_index.rs11
-rw-r--r--src/librustdoc/html/render/sidebar.rs21
-rw-r--r--src/librustdoc/html/render/span_map.rs16
-rw-r--r--src/librustdoc/html/render/tests.rs6
-rw-r--r--src/librustdoc/html/render/write_shared.rs49
-rw-r--r--src/librustdoc/html/sources.rs42
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css106
-rw-r--r--src/librustdoc/html/static/js/main.js5
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js22
-rw-r--r--src/librustdoc/html/static/js/search.js5
-rw-r--r--src/librustdoc/html/static/js/src-script.js8
-rw-r--r--src/librustdoc/html/static_files.rs28
-rw-r--r--src/librustdoc/html/templates/scraped_source.html12
-rw-r--r--src/librustdoc/html/templates/source.html10
23 files changed, 1208 insertions, 874 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index b6a73602a32..91b4b3ba1eb 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -30,120 +30,15 @@ use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length};
 use crate::clean::types::ExternalLocation;
 use crate::clean::utils::find_nearest_parent_module;
 use crate::clean::{self, ExternalCrate, PrimitiveType};
+use crate::display::Joined as _;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyText};
 use crate::html::render::Context;
-use crate::joined::Joined as _;
 use crate::passes::collect_intra_doc_links::UrlFragment;
 
-pub(crate) trait Print {
-    fn print(self, buffer: &mut Buffer);
-}
-
-impl<F> Print for F
-where
-    F: FnOnce(&mut Buffer),
-{
-    fn print(self, buffer: &mut Buffer) {
-        (self)(buffer)
-    }
-}
-
-impl Print for String {
-    fn print(self, buffer: &mut Buffer) {
-        buffer.write_str(&self);
-    }
-}
-
-impl Print for &'_ str {
-    fn print(self, buffer: &mut Buffer) {
-        buffer.write_str(self);
-    }
-}
-
-#[derive(Debug, Clone)]
-pub(crate) struct Buffer {
-    for_html: bool,
-    buffer: String,
-}
-
-impl core::fmt::Write for Buffer {
-    #[inline]
-    fn write_str(&mut self, s: &str) -> fmt::Result {
-        self.buffer.write_str(s)
-    }
-
-    #[inline]
-    fn write_char(&mut self, c: char) -> fmt::Result {
-        self.buffer.write_char(c)
-    }
-
-    #[inline]
-    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
-        self.buffer.write_fmt(args)
-    }
-}
-
-impl Buffer {
-    pub(crate) fn empty_from(v: &Buffer) -> Buffer {
-        Buffer { for_html: v.for_html, buffer: String::new() }
-    }
-
-    pub(crate) fn html() -> Buffer {
-        Buffer { for_html: true, buffer: String::new() }
-    }
-
-    pub(crate) fn new() -> Buffer {
-        Buffer { for_html: false, buffer: String::new() }
-    }
-
-    pub(crate) fn is_empty(&self) -> bool {
-        self.buffer.is_empty()
-    }
-
-    pub(crate) fn into_inner(self) -> String {
-        self.buffer
-    }
-
-    pub(crate) fn push(&mut self, c: char) {
-        self.buffer.push(c);
-    }
-
-    pub(crate) fn push_str(&mut self, s: &str) {
-        self.buffer.push_str(s);
-    }
-
-    pub(crate) fn push_buffer(&mut self, other: Buffer) {
-        self.buffer.push_str(&other.buffer);
-    }
-
-    // Intended for consumption by write! and writeln! (std::fmt) but without
-    // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
-    // import).
-    pub(crate) fn write_str(&mut self, s: &str) {
-        self.buffer.push_str(s);
-    }
-
-    // Intended for consumption by write! and writeln! (std::fmt) but without
-    // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
-    // import).
-    pub(crate) fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
-        self.buffer.write_fmt(v).unwrap();
-    }
-
-    pub(crate) fn to_display<T: Print>(mut self, t: T) -> String {
-        t.print(&mut self);
-        self.into_inner()
-    }
-
-    pub(crate) fn reserve(&mut self, additional: usize) {
-        self.buffer.reserve(additional)
-    }
-
-    pub(crate) fn len(&self) -> usize {
-        self.buffer.len()
-    }
+pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) {
+    s.write_fmt(f).unwrap();
 }
 
 pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
@@ -772,7 +667,7 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
     else {
         return String::new();
     };
-    let mut buf = Buffer::new();
+    let mut buf = String::new();
     let fqp = if *shortty == ItemType::Primitive {
         // primitives are documented in a crate, but not actually part of it
         &fqp[fqp.len() - 1..]
@@ -780,19 +675,19 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
         fqp
     };
     if let &Some(UrlFragment::Item(id)) = fragment {
-        write!(buf, "{} ", cx.tcx().def_descr(id));
+        write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id)));
         for component in fqp {
-            write!(buf, "{component}::");
+            write_str(&mut buf, format_args!("{component}::"));
         }
-        write!(buf, "{}", cx.tcx().item_name(id));
+        write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id)));
     } else if !fqp.is_empty() {
         let mut fqp_it = fqp.iter();
-        write!(buf, "{shortty} {}", fqp_it.next().unwrap());
+        write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap()));
         for component in fqp_it {
-            write!(buf, "::{component}");
+            write_str(&mut buf, format_args!("::{component}"));
         }
     }
-    buf.into_inner()
+    buf
 }
 
 /// Used to render a [`clean::Path`].
@@ -814,19 +709,22 @@ fn resolved_path(
     if w.alternate() {
         write!(w, "{}{:#}", last.name, last.args.print(cx))?;
     } else {
-        let path = if use_absolute {
-            if let Ok((_, _, fqp)) = href(did, cx) {
-                format!(
-                    "{path}::{anchor}",
-                    path = join_with_double_colon(&fqp[..fqp.len() - 1]),
-                    anchor = anchor(did, *fqp.last().unwrap(), cx)
-                )
+        let path = fmt::from_fn(|f| {
+            if use_absolute {
+                if let Ok((_, _, fqp)) = href(did, cx) {
+                    write!(
+                        f,
+                        "{path}::{anchor}",
+                        path = join_with_double_colon(&fqp[..fqp.len() - 1]),
+                        anchor = anchor(did, *fqp.last().unwrap(), cx)
+                    )
+                } else {
+                    write!(f, "{}", last.name)
+                }
             } else {
-                last.name.to_string()
+                write!(f, "{}", anchor(did, last.name, cx))
             }
-        } else {
-            anchor(did, last.name, cx).to_string()
-        };
+        });
         write!(w, "{path}{args}", args = last.args.print(cx))?;
     }
     Ok(())
@@ -854,16 +752,20 @@ fn primitive_link_fragment(
         match m.primitive_locations.get(&prim) {
             Some(&def_id) if def_id.is_local() => {
                 let len = cx.current.len();
-                let path = if len == 0 {
-                    let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
-                    format!("{cname_sym}/")
-                } else {
-                    "../".repeat(len - 1)
-                };
+                let path = fmt::from_fn(|f| {
+                    if len == 0 {
+                        let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
+                        write!(f, "{cname_sym}/")?;
+                    } else {
+                        for _ in 0..(len - 1) {
+                            f.write_str("../")?;
+                        }
+                    }
+                    Ok(())
+                });
                 write!(
                     f,
-                    "<a class=\"primitive\" href=\"{}primitive.{}.html{fragment}\">",
-                    path,
+                    "<a class=\"primitive\" href=\"{path}primitive.{}.html{fragment}\">",
                     prim.as_sym()
                 )?;
                 needs_termination = true;
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 7b2aee4b4a5..ed4b97d3625 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -14,7 +14,7 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
 use rustc_span::{BytePos, DUMMY_SP, Span};
 
-use super::format::{self, Buffer};
+use super::format::{self, write_str};
 use crate::clean::PrimitiveType;
 use crate::html::escape::EscapeBodyText;
 use crate::html::render::{Context, LinkFromSrc};
@@ -48,64 +48,80 @@ pub(crate) enum Tooltip {
 /// Highlights `src` as an inline example, returning the HTML output.
 pub(crate) fn render_example_with_highlighting(
     src: &str,
-    out: &mut Buffer,
+    out: &mut String,
     tooltip: Tooltip,
     playground_button: Option<&str>,
     extra_classes: &[String],
 ) {
     write_header(out, "rust-example-rendered", None, tooltip, extra_classes);
-    write_code(out, src, None, None);
+    write_code(out, src, None, None, None);
     write_footer(out, playground_button);
 }
 
 fn write_header(
-    out: &mut Buffer,
+    out: &mut String,
     class: &str,
-    extra_content: Option<Buffer>,
+    extra_content: Option<&str>,
     tooltip: Tooltip,
     extra_classes: &[String],
 ) {
-    write!(out, "<div class=\"example-wrap{}\">", match tooltip {
-        Tooltip::Ignore => " ignore",
-        Tooltip::CompileFail => " compile_fail",
-        Tooltip::ShouldPanic => " should_panic",
-        Tooltip::Edition(_) => " edition",
-        Tooltip::None => "",
-    },);
+    write_str(
+        out,
+        format_args!(
+            "<div class=\"example-wrap{}\">",
+            match tooltip {
+                Tooltip::Ignore => " ignore",
+                Tooltip::CompileFail => " compile_fail",
+                Tooltip::ShouldPanic => " should_panic",
+                Tooltip::Edition(_) => " edition",
+                Tooltip::None => "",
+            }
+        ),
+    );
 
     if tooltip != Tooltip::None {
         let edition_code;
-        write!(out, "<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>", match tooltip {
-            Tooltip::Ignore => "This example is not tested",
-            Tooltip::CompileFail => "This example deliberately fails to compile",
-            Tooltip::ShouldPanic => "This example panics",
-            Tooltip::Edition(edition) => {
-                edition_code = format!("This example runs with edition {edition}");
-                &edition_code
-            }
-            Tooltip::None => unreachable!(),
-        },);
+        write_str(
+            out,
+            format_args!(
+                "<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>",
+                match tooltip {
+                    Tooltip::Ignore => "This example is not tested",
+                    Tooltip::CompileFail => "This example deliberately fails to compile",
+                    Tooltip::ShouldPanic => "This example panics",
+                    Tooltip::Edition(edition) => {
+                        edition_code = format!("This example runs with edition {edition}");
+                        &edition_code
+                    }
+                    Tooltip::None => unreachable!(),
+                }
+            ),
+        );
     }
 
     if let Some(extra) = extra_content {
-        out.push_buffer(extra);
+        out.push_str(&extra);
     }
     if class.is_empty() {
-        write!(
+        write_str(
             out,
-            "<pre class=\"rust{}{}\">",
-            if extra_classes.is_empty() { "" } else { " " },
-            extra_classes.join(" "),
+            format_args!(
+                "<pre class=\"rust{}{}\">",
+                if extra_classes.is_empty() { "" } else { " " },
+                extra_classes.join(" ")
+            ),
         );
     } else {
-        write!(
+        write_str(
             out,
-            "<pre class=\"rust {class}{}{}\">",
-            if extra_classes.is_empty() { "" } else { " " },
-            extra_classes.join(" "),
+            format_args!(
+                "<pre class=\"rust {class}{}{}\">",
+                if extra_classes.is_empty() { "" } else { " " },
+                extra_classes.join(" ")
+            ),
         );
     }
-    write!(out, "<code>");
+    write_str(out, format_args!("<code>"));
 }
 
 /// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
@@ -142,6 +158,7 @@ struct TokenHandler<'a, 'tcx, F: Write> {
     /// used to generate links.
     pending_elems: Vec<(&'a str, Option<Class>)>,
     href_context: Option<HrefContext<'a, 'tcx>>,
+    write_line_number: fn(&mut F, u32, &'static str),
 }
 
 impl<F: Write> TokenHandler<'_, '_, F> {
@@ -174,7 +191,14 @@ impl<F: Write> TokenHandler<'_, '_, F> {
             && can_merge(current_class, Some(*parent_class), "")
         {
             for (text, class) in self.pending_elems.iter() {
-                string(self.out, EscapeBodyText(text), *class, &self.href_context, false);
+                string(
+                    self.out,
+                    EscapeBodyText(text),
+                    *class,
+                    &self.href_context,
+                    false,
+                    self.write_line_number,
+                );
             }
         } else {
             // We only want to "open" the tag ourselves if we have more than one pending and if the
@@ -196,6 +220,7 @@ impl<F: Write> TokenHandler<'_, '_, F> {
                     *class,
                     &self.href_context,
                     close_tag.is_none(),
+                    self.write_line_number,
                 );
             }
             if let Some(close_tag) = close_tag {
@@ -205,6 +230,11 @@ impl<F: Write> TokenHandler<'_, '_, F> {
         self.pending_elems.clear();
         true
     }
+
+    #[inline]
+    fn write_line_number(&mut self, line: u32, extra: &'static str) {
+        (self.write_line_number)(&mut self.out, line, extra);
+    }
 }
 
 impl<F: Write> Drop for TokenHandler<'_, '_, F> {
@@ -218,6 +248,43 @@ impl<F: Write> Drop for TokenHandler<'_, '_, F> {
     }
 }
 
+fn write_scraped_line_number(out: &mut impl Write, line: u32, extra: &'static str) {
+    // https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
+    // Do not show "1 2 3 4 5 ..." in web search results.
+    write!(out, "{extra}<span data-nosnippet>{line}</span>",).unwrap();
+}
+
+fn write_line_number(out: &mut impl Write, line: u32, extra: &'static str) {
+    // https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
+    // Do not show "1 2 3 4 5 ..." in web search results.
+    write!(out, "{extra}<a href=#{line} id={line} data-nosnippet>{line}</a>",).unwrap();
+}
+
+fn empty_line_number(out: &mut impl Write, _: u32, extra: &'static str) {
+    out.write_str(extra).unwrap();
+}
+
+#[derive(Clone, Copy)]
+pub(super) struct LineInfo {
+    pub(super) start_line: u32,
+    max_lines: u32,
+    pub(super) is_scraped_example: bool,
+}
+
+impl LineInfo {
+    pub(super) fn new(max_lines: u32) -> Self {
+        Self { start_line: 1, max_lines: max_lines + 1, is_scraped_example: false }
+    }
+
+    pub(super) fn new_scraped(max_lines: u32, start_line: u32) -> Self {
+        Self {
+            start_line: start_line + 1,
+            max_lines: max_lines + start_line + 1,
+            is_scraped_example: true,
+        }
+    }
+}
+
 /// Convert the given `src` source code into HTML by adding classes for highlighting.
 ///
 /// This code is used to render code blocks (in the documentation) as well as the source code pages.
@@ -234,6 +301,7 @@ pub(super) fn write_code(
     src: &str,
     href_context: Option<HrefContext<'_, '_>>,
     decoration_info: Option<&DecorationInfo>,
+    line_info: Option<LineInfo>,
 ) {
     // This replace allows to fix how the code source with DOS backline characters is displayed.
     let src = src.replace("\r\n", "\n");
@@ -244,6 +312,23 @@ pub(super) fn write_code(
         current_class: None,
         pending_elems: Vec::new(),
         href_context,
+        write_line_number: match line_info {
+            Some(line_info) => {
+                if line_info.is_scraped_example {
+                    write_scraped_line_number
+                } else {
+                    write_line_number
+                }
+            }
+            None => empty_line_number,
+        },
+    };
+
+    let (mut line, max_lines) = if let Some(line_info) = line_info {
+        token_handler.write_line_number(line_info.start_line, "");
+        (line_info.start_line, line_info.max_lines)
+    } else {
+        (0, u32::MAX)
     };
 
     Classifier::new(
@@ -274,7 +359,14 @@ pub(super) fn write_code(
                 if need_current_class_update {
                     token_handler.current_class = class.map(Class::dummy);
                 }
-                token_handler.pending_elems.push((text, class));
+                if text == "\n" {
+                    line += 1;
+                    if line < max_lines {
+                        token_handler.pending_elems.push((text, Some(Class::Backline(line))));
+                    }
+                } else {
+                    token_handler.pending_elems.push((text, class));
+                }
             }
             Highlight::EnterSpan { class } => {
                 let mut should_add = true;
@@ -314,8 +406,8 @@ pub(super) fn write_code(
     });
 }
 
-fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
-    writeln!(out, "</code></pre>{}</div>", playground_button.unwrap_or_default());
+fn write_footer(out: &mut String, playground_button: Option<&str>) {
+    write_str(out, format_args_nl!("</code></pre>{}</div>", playground_button.unwrap_or_default()));
 }
 
 /// How a span of text is classified. Mostly corresponds to token kinds.
@@ -340,6 +432,7 @@ enum Class {
     PreludeVal(Span),
     QuestionMark,
     Decoration(&'static str),
+    Backline(u32),
 }
 
 impl Class {
@@ -388,6 +481,7 @@ impl Class {
             Class::PreludeVal(_) => "prelude-val",
             Class::QuestionMark => "question-mark",
             Class::Decoration(kind) => kind,
+            Class::Backline(_) => "",
         }
     }
 
@@ -411,7 +505,8 @@ impl Class {
             | Self::Bool
             | Self::Lifetime
             | Self::QuestionMark
-            | Self::Decoration(_) => None,
+            | Self::Decoration(_)
+            | Self::Backline(_) => None,
         }
     }
 }
@@ -686,8 +781,13 @@ impl<'src> Classifier<'src> {
     ) {
         let lookahead = self.peek();
         let no_highlight = |sink: &mut dyn FnMut(_)| sink(Highlight::Token { text, class: None });
+        let whitespace = |sink: &mut dyn FnMut(_)| {
+            for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) {
+                sink(Highlight::Token { text: part, class: None });
+            }
+        };
         let class = match token {
-            TokenKind::Whitespace => return no_highlight(sink),
+            TokenKind::Whitespace => return whitespace(sink),
             TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => {
                 if doc_style.is_some() {
                     Class::DocComment
@@ -708,7 +808,7 @@ impl<'src> Classifier<'src> {
             // or a reference or pointer type. Unless, of course, it looks like
             // a logical and or a multiplication operator: `&&` or `* `.
             TokenKind::Star => match self.tokens.peek() {
-                Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
+                Some((TokenKind::Whitespace, _)) => return whitespace(sink),
                 Some((TokenKind::Ident, "mut")) => {
                     self.next();
                     sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
@@ -732,7 +832,7 @@ impl<'src> Classifier<'src> {
                     sink(Highlight::Token { text: "&=", class: None });
                     return;
                 }
-                Some((TokenKind::Whitespace, _)) => return no_highlight(sink),
+                Some((TokenKind::Whitespace, _)) => return whitespace(sink),
                 Some((TokenKind::Ident, "mut")) => {
                     self.next();
                     sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
@@ -879,7 +979,9 @@ impl<'src> Classifier<'src> {
         };
         // Anything that didn't return above is the simple case where we the
         // class just spans a single token, so we can use the `string` method.
-        sink(Highlight::Token { text, class: Some(class) });
+        for part in text.split('\n').intersperse("\n").filter(|s| !s.is_empty()) {
+            sink(Highlight::Token { text: part, class: Some(class) });
+        }
     }
 
     fn peek(&mut self) -> Option<TokenKind> {
@@ -931,14 +1033,18 @@ fn exit_span(out: &mut impl Write, closing_tag: &str) {
 /// Note that if `context` is not `None` and that the given `klass` contains a `Span`, the function
 /// will then try to find this `span` in the `span_correspondence_map`. If found, it'll then
 /// generate a link for this element (which corresponds to where its definition is located).
-fn string<T: Display>(
-    out: &mut impl Write,
+fn string<T: Display, W: Write>(
+    out: &mut W,
     text: T,
     klass: Option<Class>,
     href_context: &Option<HrefContext<'_, '_>>,
     open_tag: bool,
+    write_line_number_callback: fn(&mut W, u32, &'static str),
 ) {
-    if let Some(closing_tag) = string_without_closing_tag(out, text, klass, href_context, open_tag)
+    if let Some(Class::Backline(line)) = klass {
+        write_line_number_callback(out, line, "\n");
+    } else if let Some(closing_tag) =
+        string_without_closing_tag(out, text, klass, href_context, open_tag)
     {
         out.write_str(closing_tag).unwrap();
     }
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index fccbb98f80f..2603e887bea 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -3,7 +3,6 @@ use rustc_data_structures::fx::FxIndexMap;
 use rustc_span::create_default_session_globals_then;
 
 use super::{DecorationInfo, write_code};
-use crate::html::format::Buffer;
 
 const STYLE: &str = r#"
 <style>
@@ -22,9 +21,9 @@ fn test_html_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/sample.rs");
         let html = {
-            let mut out = Buffer::new();
-            write_code(&mut out, src, None, None);
-            format!("{STYLE}<pre><code>{}</code></pre>\n", out.into_inner())
+            let mut out = String::new();
+            write_code(&mut out, src, None, None, None);
+            format!("{STYLE}<pre><code>{out}</code></pre>\n")
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
     });
@@ -36,9 +35,9 @@ fn test_dos_backline() {
         let src = "pub fn foo() {\r\n\
     println!(\"foo\");\r\n\
 }\r\n";
-        let mut html = Buffer::new();
-        write_code(&mut html, src, None, None);
-        expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
+        let mut html = String::new();
+        write_code(&mut html, src, None, None, None);
+        expect_file!["fixtures/dos_line.html"].assert_eq(&html);
     });
 }
 
@@ -50,9 +49,9 @@ use self::whatever;
 let x = super::b::foo;
 let y = Self::whatever;";
 
-        let mut html = Buffer::new();
-        write_code(&mut html, src, None, None);
-        expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
+        let mut html = String::new();
+        write_code(&mut html, src, None, None, None);
+        expect_file!["fixtures/highlight.html"].assert_eq(&html);
     });
 }
 
@@ -60,9 +59,9 @@ let y = Self::whatever;";
 fn test_union_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/union.rs");
-        let mut html = Buffer::new();
-        write_code(&mut html, src, None, None);
-        expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
+        let mut html = String::new();
+        write_code(&mut html, src, None, None, None);
+        expect_file!["fixtures/union.html"].assert_eq(&html);
     });
 }
 
@@ -77,8 +76,8 @@ let a = 4;";
         decorations.insert("example", vec![(0, 10), (11, 21)]);
         decorations.insert("example2", vec![(22, 32)]);
 
-        let mut html = Buffer::new();
-        write_code(&mut html, src, None, Some(&DecorationInfo(decorations)));
-        expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
+        let mut html = String::new();
+        write_code(&mut html, src, None, Some(&DecorationInfo(decorations)), None);
+        expect_file!["fixtures/decorations.html"].assert_eq(&html);
     });
 }
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index d957cf1b569..df70df062fe 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -1,3 +1,4 @@
+use std::fmt::{self, Display};
 use std::path::PathBuf;
 
 use rinja::Template;
@@ -5,7 +6,6 @@ use rustc_data_structures::fx::FxIndexMap;
 
 use super::static_files::{STATIC_FILES, StaticFiles};
 use crate::externalfiles::ExternalHtml;
-use crate::html::format::{Buffer, Print};
 use crate::html::render::{StylePath, ensure_trailing_slash};
 
 #[derive(Clone)]
@@ -71,7 +71,24 @@ struct PageLayout<'a> {
 
 pub(crate) use crate::html::render::sidebar::filters;
 
-pub(crate) fn render<T: Print, S: Print>(
+/// Implements [`Display`] for a function that accepts a mutable reference to a [`String`], and (optionally) writes to it.
+///
+/// The wrapped function will receive an empty string, and can modify it,
+/// and the `Display` implementation will write the contents of the string after the function has finished.
+pub(crate) struct BufDisplay<F>(pub F);
+
+impl<F> Display for BufDisplay<F>
+where
+    F: Fn(&mut String),
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut buf = String::new();
+        self.0(&mut buf);
+        f.write_str(&buf)
+    }
+}
+
+pub(crate) fn render<T: Display, S: Display>(
     layout: &Layout,
     page: &Page<'_>,
     sidebar: S,
@@ -98,8 +115,8 @@ pub(crate) fn render<T: Print, S: Print>(
     let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
     themes.sort();
 
-    let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
-    let sidebar = Buffer::html().to_display(sidebar);
+    let content = t.to_string(); // Note: This must happen before making the sidebar.
+    let sidebar = sidebar.to_string();
     PageLayout {
         static_root_path,
         page,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 7e835585b73..d9e49577d39 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -38,7 +38,7 @@ use std::sync::{Arc, Weak};
 use pulldown_cmark::{
     BrokenLink, CodeBlockKind, CowStr, Event, LinkType, Options, Parser, Tag, TagEnd, html,
 };
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Diag, DiagMessage};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::ty::TyCtxt;
@@ -52,7 +52,6 @@ use crate::clean::RenderedLink;
 use crate::doctest;
 use crate::doctest::GlobalTestOptions;
 use crate::html::escape::{Escape, EscapeBodyText};
-use crate::html::format::Buffer;
 use crate::html::highlight;
 use crate::html::length_limit::HtmlWithLimit;
 use crate::html::render::small_url_encode;
@@ -140,7 +139,7 @@ impl ErrorCodes {
 /// Controls whether a line will be hidden or shown in HTML output.
 ///
 /// All lines are used in documentation tests.
-enum Line<'a> {
+pub(crate) enum Line<'a> {
     Hidden(&'a str),
     Shown(Cow<'a, str>),
 }
@@ -153,7 +152,7 @@ impl<'a> Line<'a> {
         }
     }
 
-    fn for_code(self) -> Cow<'a, str> {
+    pub(crate) fn for_code(self) -> Cow<'a, str> {
         match self {
             Line::Shown(l) => l,
             Line::Hidden(l) => Cow::Borrowed(l),
@@ -161,12 +160,14 @@ impl<'a> Line<'a> {
     }
 }
 
+/// This function is used to handle the "hidden lines" (ie starting with `#`) in
+/// doctests. It also transforms `##` back into `#`.
 // FIXME: There is a minor inconsistency here. For lines that start with ##, we
 // have no easy way of removing a potential single space after the hashes, which
 // is done in the single # case. This inconsistency seems okay, if non-ideal. In
 // order to fix it we'd have to iterate to find the first non-# character, and
 // then reallocate to remove it; which would make us return a String.
-fn map_line(s: &str) -> Line<'_> {
+pub(crate) fn map_line(s: &str) -> Line<'_> {
     let trimmed = s.trim();
     if trimmed.starts_with("##") {
         Line::Shown(Cow::Owned(s.replacen("##", "#", 1)))
@@ -329,7 +330,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
 
         // insert newline to clearly separate it from the
         // previous block so we can shorten the html output
-        let mut s = Buffer::new();
+        let mut s = String::new();
         s.push('\n');
 
         highlight::render_example_with_highlighting(
@@ -339,7 +340,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
             playground_button.as_deref(),
             &added_classes,
         );
-        Some(Event::Html(s.into_inner().into()))
+        Some(Event::Html(s.into()))
     }
 }
 
@@ -1762,6 +1763,46 @@ pub(crate) fn markdown_links<'md, R>(
         }
     };
 
+    let span_for_refdef = |link: &CowStr<'_>, span: Range<usize>| {
+        // We want to underline the link's definition, but `span` will point at the entire refdef.
+        // Skip the label, then try to find the entire URL.
+        let mut square_brace_count = 0;
+        let mut iter = md.as_bytes()[span.start..span.end].iter().copied().enumerate();
+        for (_i, c) in &mut iter {
+            match c {
+                b':' if square_brace_count == 0 => break,
+                b'[' => square_brace_count += 1,
+                b']' => square_brace_count -= 1,
+                _ => {}
+            }
+        }
+        while let Some((i, c)) = iter.next() {
+            if c == b'<' {
+                while let Some((j, c)) = iter.next() {
+                    match c {
+                        b'\\' => {
+                            let _ = iter.next();
+                        }
+                        b'>' => {
+                            return MarkdownLinkRange::Destination(
+                                i + 1 + span.start..j + span.start,
+                            );
+                        }
+                        _ => {}
+                    }
+                }
+            } else if !c.is_ascii_whitespace() {
+                while let Some((j, c)) = iter.next() {
+                    if c.is_ascii_whitespace() {
+                        return MarkdownLinkRange::Destination(i + span.start..j + span.start);
+                    }
+                }
+                return MarkdownLinkRange::Destination(i + span.start..span.end);
+            }
+        }
+        span_for_link(link, span)
+    };
+
     let span_for_offset_backward = |span: Range<usize>, open: u8, close: u8| {
         let mut open_brace = !0;
         let mut close_brace = !0;
@@ -1843,9 +1884,16 @@ pub(crate) fn markdown_links<'md, R>(
     .into_offset_iter();
     let mut links = Vec::new();
 
+    let mut refdefs = FxIndexMap::default();
+    for (label, refdef) in event_iter.reference_definitions().iter() {
+        refdefs.insert(label.to_string(), (false, refdef.dest.to_string(), refdef.span.clone()));
+    }
+
     for (event, span) in event_iter {
         match event {
-            Event::Start(Tag::Link { link_type, dest_url, .. }) if may_be_doc_link(link_type) => {
+            Event::Start(Tag::Link { link_type, dest_url, id, .. })
+                if may_be_doc_link(link_type) =>
+            {
                 let range = match link_type {
                     // Link is pulled from the link itself.
                     LinkType::ReferenceUnknown | LinkType::ShortcutUnknown => {
@@ -1855,7 +1903,12 @@ pub(crate) fn markdown_links<'md, R>(
                     LinkType::Inline => span_for_offset_backward(span, b'(', b')'),
                     // Link is pulled from elsewhere in the document.
                     LinkType::Reference | LinkType::Collapsed | LinkType::Shortcut => {
-                        span_for_link(&dest_url, span)
+                        if let Some((is_used, dest_url, span)) = refdefs.get_mut(&id[..]) {
+                            *is_used = true;
+                            span_for_refdef(&CowStr::from(&dest_url[..]), span.clone())
+                        } else {
+                            span_for_link(&dest_url, span)
+                        }
                     }
                     LinkType::Autolink | LinkType::Email => unreachable!(),
                 };
@@ -1872,6 +1925,18 @@ pub(crate) fn markdown_links<'md, R>(
         }
     }
 
+    for (_label, (is_used, dest_url, span)) in refdefs.into_iter() {
+        if !is_used
+            && let Some(link) = preprocess_link(MarkdownLink {
+                kind: LinkType::Reference,
+                range: span_for_refdef(&CowStr::from(&dest_url[..]), span),
+                link: dest_url,
+            })
+        {
+            links.push(link);
+        }
+    }
+
     links
 }
 
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 2001a763c09..bb42b877a2c 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -275,14 +275,14 @@ fn test_lang_string_tokenizer() {
     case("foo", &[LangStringToken::LangToken("foo")]);
     case("foo,bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
     case(".foo,.bar", &[]);
-    case("{.foo,.bar}", &[
-        LangStringToken::ClassAttribute("foo"),
-        LangStringToken::ClassAttribute("bar"),
-    ]);
-    case("  {.foo,.bar}  ", &[
-        LangStringToken::ClassAttribute("foo"),
-        LangStringToken::ClassAttribute("bar"),
-    ]);
+    case(
+        "{.foo,.bar}",
+        &[LangStringToken::ClassAttribute("foo"), LangStringToken::ClassAttribute("bar")],
+    );
+    case(
+        "  {.foo,.bar}  ",
+        &[LangStringToken::ClassAttribute("foo"), LangStringToken::ClassAttribute("bar")],
+    );
     case("foo bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
     case("foo\tbar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
     case("foo\t, bar", &[LangStringToken::LangToken("foo"), LangStringToken::LangToken("bar")]);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 1cefdf96bbc..146bdd34069 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -1,5 +1,6 @@
 use std::cell::RefCell;
 use std::collections::BTreeMap;
+use std::fmt::{self, Write as _};
 use std::io;
 use std::path::{Path, PathBuf};
 use std::sync::mpsc::{Receiver, channel};
@@ -26,11 +27,12 @@ use crate::formats::FormatRenderer;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
-use crate::html::format::{Buffer, join_with_double_colon};
+use crate::html::format::join_with_double_colon;
+use crate::html::layout::{self, BufDisplay};
 use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
 use crate::html::render::write_shared::write_shared;
 use crate::html::url_parts_builder::UrlPartsBuilder;
-use crate::html::{layout, sources, static_files};
+use crate::html::{sources, static_files};
 use crate::scrape_examples::AllCallLocations;
 use crate::{DOC_RUST_LANG_ORG_VERSION, try_err};
 
@@ -235,7 +237,7 @@ impl<'tcx> Context<'tcx> {
         };
 
         if !render_redirect_pages {
-            let mut page_buffer = Buffer::html();
+            let mut page_buffer = String::new();
             print_item(self, it, &mut page_buffer);
             let page = layout::Page {
                 css_class: tyname_s,
@@ -249,8 +251,10 @@ impl<'tcx> Context<'tcx> {
             layout::render(
                 &self.shared.layout,
                 &page,
-                |buf: &mut _| print_sidebar(self, it, buf),
-                move |buf: &mut Buffer| buf.push_buffer(page_buffer),
+                BufDisplay(|buf: &mut String| {
+                    print_sidebar(self, it, buf);
+                }),
+                page_buffer,
                 &self.shared.style_files,
             )
         } else {
@@ -262,12 +266,12 @@ impl<'tcx> Context<'tcx> {
                     // preventing an infinite redirection loop in the generated
                     // documentation.
 
-                    let mut path = String::new();
-                    for name in &names[..names.len() - 1] {
-                        path.push_str(name.as_str());
-                        path.push('/');
-                    }
-                    path.push_str(&item_path(ty, names.last().unwrap().as_str()));
+                    let path = fmt::from_fn(|f| {
+                        for name in &names[..names.len() - 1] {
+                            write!(f, "{name}/")?;
+                        }
+                        write!(f, "{}", item_path(ty, names.last().unwrap().as_str()))
+                    });
                     match self.shared.redirections {
                         Some(ref redirections) => {
                             let mut current_path = String::new();
@@ -275,8 +279,12 @@ impl<'tcx> Context<'tcx> {
                                 current_path.push_str(name.as_str());
                                 current_path.push('/');
                             }
-                            current_path.push_str(&item_path(ty, names.last().unwrap().as_str()));
-                            redirections.borrow_mut().insert(current_path, path);
+                            let _ = write!(
+                                current_path,
+                                "{}",
+                                item_path(ty, names.last().unwrap().as_str())
+                            );
+                            redirections.borrow_mut().insert(current_path, path.to_string());
                         }
                         None => {
                             return layout::redirect(&format!(
@@ -627,7 +635,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
             rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
         };
         let all = shared.all.replace(AllTypes::new());
-        let mut sidebar = Buffer::html();
+        let mut sidebar = String::new();
 
         // all.html is not customizable, so a blank id map is fine
         let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new(), ModuleLike::Crate);
@@ -646,8 +654,10 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         let v = layout::render(
             &shared.layout,
             &page,
-            sidebar.into_inner(),
-            |buf: &mut Buffer| all.print(buf),
+            sidebar,
+            BufDisplay(|buf: &mut String| {
+                all.print(buf);
+            }),
             &shared.style_files,
         );
         shared.fs.write(final_file, v)?;
@@ -665,7 +675,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                 &shared.layout,
                 &page,
                 sidebar,
-                |buf: &mut Buffer| {
+                fmt::from_fn(|buf| {
                     write!(
                         buf,
                         "<div class=\"main-heading\">\
@@ -684,7 +694,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                          <script defer src=\"{static_root_path}{settings_js}\"></script>",
                         static_root_path = page.get_static_root_path(),
                         settings_js = static_files::STATIC_FILES.settings_js,
-                    );
+                    )?;
                     // Pre-load all theme CSS files, so that switching feels seamless.
                     //
                     // When loading settings.html as a popover, the equivalent HTML is
@@ -697,10 +707,11 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                                     as=\"style\">",
                                 root_path = page.static_root_path.unwrap_or(""),
                                 suffix = page.resource_suffix,
-                            );
+                            )?;
                         }
                     }
-                },
+                    Ok(())
+                }),
                 &shared.style_files,
             );
             shared.fs.write(settings_file, v)?;
@@ -716,25 +727,22 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                 &shared.layout,
                 &page,
                 sidebar,
-                |buf: &mut Buffer| {
-                    write!(
-                        buf,
-                        "<div class=\"main-heading\">\
-                         <h1>Rustdoc help</h1>\
-                         <span class=\"out-of-band\">\
-                             <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
-                                Back\
-                            </a>\
-                         </span>\
-                         </div>\
-                         <noscript>\
-                            <section>\
-                                <p>You need to enable JavaScript to use keyboard commands or search.</p>\
-                                <p>For more information, browse the <a href=\"{DOC_RUST_LANG_ORG_VERSION}/rustdoc/\">rustdoc handbook</a>.</p>\
-                            </section>\
-                         </noscript>",
-                    )
-                },
+                format_args!(
+                    "<div class=\"main-heading\">\
+                        <h1>Rustdoc help</h1>\
+                        <span class=\"out-of-band\">\
+                            <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
+                            Back\
+                        </a>\
+                        </span>\
+                        </div>\
+                        <noscript>\
+                        <section>\
+                            <p>You need to enable JavaScript to use keyboard commands or search.</p>\
+                            <p>For more information, browse the <a href=\"{DOC_RUST_LANG_ORG_VERSION}/rustdoc/\">rustdoc handbook</a>.</p>\
+                        </section>\
+                        </noscript>",
+                ),
                 &shared.style_files,
             );
             shared.fs.write(help_file, v)?;
@@ -851,9 +859,9 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         if !buf.is_empty() {
             let name = item.name.as_ref().unwrap();
             let item_type = item.type_();
-            let file_name = &item_path(item_type, name.as_str());
+            let file_name = item_path(item_type, name.as_str()).to_string();
             self.shared.ensure_dir(&self.dst)?;
-            let joint_dst = self.dst.join(file_name);
+            let joint_dst = self.dst.join(&file_name);
             self.shared.fs.write(joint_dst, buf)?;
 
             if !self.info.render_redirect_pages {
@@ -870,7 +878,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
                         format!("{crate_name}/{file_name}"),
                     );
                 } else {
-                    let v = layout::redirect(file_name);
+                    let v = layout::redirect(&file_name);
                     let redir_dst = self.dst.join(redir_name);
                     self.shared.fs.write(redir_dst, v)?;
                 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f7dcb87e4f3..204631063a2 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -63,15 +63,16 @@ pub(crate) use self::context::*;
 pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
 pub(crate) use self::write_shared::*;
 use crate::clean::{self, ItemId, RenderedLink};
+use crate::display::{Joined as _, MaybeDisplay as _};
 use crate::error::Error;
 use crate::formats::Impl;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::Escape;
 use crate::html::format::{
-    Buffer, Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
+    Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
     print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause,
-    visibility_print_with_space,
+    visibility_print_with_space, write_str,
 };
 use crate::html::markdown::{
     HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
@@ -436,27 +437,29 @@ impl AllTypes {
         sections
     }
 
-    fn print(self, f: &mut Buffer) {
-        fn print_entries(f: &mut Buffer, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
+    fn print(&self, f: &mut String) {
+        fn print_entries(f: &mut String, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
             if !e.is_empty() {
                 let mut e: Vec<&ItemEntry> = e.iter().collect();
                 e.sort();
-                write!(
+                write_str(
                     f,
-                    "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
-                    id = kind.id(),
-                    title = kind.name(),
+                    format_args!(
+                        "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
+                        id = kind.id(),
+                        title = kind.name(),
+                    ),
                 );
 
                 for s in e.iter() {
-                    write!(f, "<li>{}</li>", s.print());
+                    write_str(f, format_args!("<li>{}</li>", s.print()));
                 }
 
-                f.write_str("</ul>");
+                f.push_str("</ul>");
             }
         }
 
-        f.write_str("<h1>List of all items</h1>");
+        f.push_str("<h1>List of all items</h1>");
         // Note: print_entries does not escape the title, because we know the current set of titles
         // doesn't require escaping.
         print_entries(f, &self.structs, ItemSection::Structs);
@@ -566,17 +569,27 @@ fn document_short<'a, 'cx: 'a>(
             let (mut summary_html, has_more_content) =
                 MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
 
-            if has_more_content {
-                let link = format!(" <a{}>Read more</a>", assoc_href_attr(item, link, cx));
+            let link = if has_more_content {
+                let link = fmt::from_fn(|f| {
+                    write!(
+                        f,
+                        " <a{}>Read more</a>",
+                        assoc_href_attr(item, link, cx).maybe_display()
+                    )
+                });
 
                 if let Some(idx) = summary_html.rfind("</p>") {
-                    summary_html.insert_str(idx, &link);
+                    summary_html.insert_str(idx, &link.to_string());
+                    None
                 } else {
-                    summary_html.push_str(&link);
+                    Some(link)
                 }
+            } else {
+                None
             }
+            .maybe_display();
 
-            write!(f, "<div class='docblock'>{summary_html}</div>")?;
+            write!(f, "<div class='docblock'>{summary_html}{link}</div>")?;
         }
         Ok(())
     })
@@ -761,7 +774,7 @@ pub(crate) fn render_impls(
             let did = i.trait_did().unwrap();
             let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx());
             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
-            let mut buffer = Buffer::new();
+            let mut buffer = String::new();
             render_impl(
                 &mut buffer,
                 cx,
@@ -778,7 +791,7 @@ pub(crate) fn render_impls(
                     toggle_open_by_default,
                 },
             );
-            buffer.into_inner()
+            buffer
         })
         .collect::<Vec<_>>();
     rendered_impls.sort();
@@ -786,13 +799,23 @@ pub(crate) fn render_impls(
 }
 
 /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
-fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
+fn assoc_href_attr<'a, 'tcx>(
+    it: &clean::Item,
+    link: AssocItemLink<'a>,
+    cx: &Context<'tcx>,
+) -> Option<impl fmt::Display + 'a + Captures<'tcx>> {
     let name = it.name.unwrap();
     let item_type = it.type_();
 
+    enum Href<'a> {
+        AnchorId(&'a str),
+        Anchor(ItemType),
+        Url(String, ItemType),
+    }
+
     let href = match link {
-        AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{id}")),
-        AssocItemLink::Anchor(None) => Some(format!("#{item_type}.{name}")),
+        AssocItemLink::Anchor(Some(ref id)) => Href::AnchorId(id),
+        AssocItemLink::Anchor(None) => Href::Anchor(item_type),
         AssocItemLink::GotoSource(did, provided_methods) => {
             // We're creating a link from the implementation of an associated item to its
             // declaration in the trait declaration.
@@ -812,7 +835,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
             };
 
             match href(did.expect_def_id(), cx) {
-                Ok((url, ..)) => Some(format!("{url}#{item_type}.{name}")),
+                Ok((url, ..)) => Href::Url(url, item_type),
                 // The link is broken since it points to an external crate that wasn't documented.
                 // Do not create any link in such case. This is better than falling back to a
                 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -824,15 +847,25 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
                 // those two items are distinct!
                 // In this scenario, the actual `id` of this impl item would be
                 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
-                Err(HrefError::DocumentationNotBuilt) => None,
-                Err(_) => Some(format!("#{item_type}.{name}")),
+                Err(HrefError::DocumentationNotBuilt) => return None,
+                Err(_) => Href::Anchor(item_type),
             }
         }
     };
 
+    let href = fmt::from_fn(move |f| match &href {
+        Href::AnchorId(id) => write!(f, "#{id}"),
+        Href::Url(url, item_type) => {
+            write!(f, "{url}#{item_type}.{name}")
+        }
+        Href::Anchor(item_type) => {
+            write!(f, "#{item_type}.{name}")
+        }
+    });
+
     // If there is no `href` for the reason explained above, simply do not render it which is valid:
     // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
-    href.map(|href| format!(" href=\"{href}\"")).unwrap_or_default()
+    Some(fmt::from_fn(move |f| write!(f, " href=\"{href}\"")))
 }
 
 #[derive(Debug)]
@@ -847,7 +880,7 @@ enum AssocConstValue<'a> {
 }
 
 fn assoc_const(
-    w: &mut Buffer,
+    w: &mut String,
     it: &clean::Item,
     generics: &clean::Generics,
     ty: &clean::Type,
@@ -857,15 +890,17 @@ fn assoc_const(
     cx: &Context<'_>,
 ) {
     let tcx = cx.tcx();
-    write!(
+    write_str(
         w,
-        "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
-        indent = " ".repeat(indent),
-        vis = visibility_print_with_space(it, cx),
-        href = assoc_href_attr(it, link, cx),
-        name = it.name.as_ref().unwrap(),
-        generics = generics.print(cx),
-        ty = ty.print(cx),
+        format_args!(
+            "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
+            indent = " ".repeat(indent),
+            vis = visibility_print_with_space(it, cx),
+            href = assoc_href_attr(it, link, cx).maybe_display(),
+            name = it.name.as_ref().unwrap(),
+            generics = generics.print(cx),
+            ty = ty.print(cx),
+        ),
     );
     if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
         // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
@@ -879,14 +914,14 @@ fn assoc_const(
             AssocConstValue::Impl(_) => repr != "_",  // show if there is a meaningful value to show
             AssocConstValue::None => unreachable!(),
         } {
-            write!(w, " = {}", Escape(&repr));
+            write_str(w, format_args!(" = {}", Escape(&repr)));
         }
     }
-    write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
+    write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline)));
 }
 
 fn assoc_type(
-    w: &mut Buffer,
+    w: &mut String,
     it: &clean::Item,
     generics: &clean::Generics,
     bounds: &[clean::GenericBound],
@@ -895,27 +930,29 @@ fn assoc_type(
     indent: usize,
     cx: &Context<'_>,
 ) {
-    write!(
+    write_str(
         w,
-        "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
-        indent = " ".repeat(indent),
-        vis = visibility_print_with_space(it, cx),
-        href = assoc_href_attr(it, link, cx),
-        name = it.name.as_ref().unwrap(),
-        generics = generics.print(cx),
+        format_args!(
+            "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
+            indent = " ".repeat(indent),
+            vis = visibility_print_with_space(it, cx),
+            href = assoc_href_attr(it, link, cx).maybe_display(),
+            name = it.name.as_ref().unwrap(),
+            generics = generics.print(cx),
+        ),
     );
     if !bounds.is_empty() {
-        write!(w, ": {}", print_generic_bounds(bounds, cx))
+        write_str(w, format_args!(": {}", print_generic_bounds(bounds, cx)));
     }
     // Render the default before the where-clause which aligns with the new recommended style. See #89122.
     if let Some(default) = default {
-        write!(w, " = {}", default.print(cx))
+        write_str(w, format_args!(" = {}", default.print(cx)));
     }
-    write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
+    write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline)));
 }
 
 fn assoc_method(
-    w: &mut Buffer,
+    w: &mut String,
     meth: &clean::Item,
     g: &clean::Generics,
     d: &clean::FnDecl,
@@ -942,7 +979,7 @@ fn assoc_method(
     let asyncness = header.asyncness.print_with_space();
     let safety = header.safety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
-    let href = assoc_href_attr(meth, link, cx);
+    let href = assoc_href_attr(meth, link, cx).maybe_display();
 
     // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
     let generics_len = format!("{:#}", g.print(cx)).len();
@@ -956,35 +993,36 @@ fn assoc_method(
         + name.as_str().len()
         + generics_len;
 
-    let notable_traits = notable_traits_button(&d.output, cx);
+    let notable_traits = notable_traits_button(&d.output, cx).maybe_display();
 
     let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
         header_len += 4;
         let indent_str = "    ";
-        write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx));
+        write_str(w, format_args!("{}", render_attributes_in_pre(meth, indent_str, cx)));
         (4, indent_str, Ending::NoNewline)
     } else {
         render_attributes_in_code(w, meth, cx);
         (0, "", Ending::Newline)
     };
     w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
-    write!(
+    write_str(
         w,
-        "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
+        format_args!(
+            "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
          <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
-        indent = indent_str,
-        vis = vis,
-        defaultness = defaultness,
-        constness = constness,
-        asyncness = asyncness,
-        safety = safety,
-        abi = abi,
-        href = href,
-        name = name,
-        generics = g.print(cx),
-        decl = d.full_print(header_len, indent, cx),
-        notable_traits = notable_traits.unwrap_or_default(),
-        where_clause = print_where_clause(g, cx, indent, end_newline),
+            indent = indent_str,
+            vis = vis,
+            defaultness = defaultness,
+            constness = constness,
+            asyncness = asyncness,
+            safety = safety,
+            abi = abi,
+            href = href,
+            name = name,
+            generics = g.print(cx),
+            decl = d.full_print(header_len, indent, cx),
+            where_clause = print_where_clause(g, cx, indent, end_newline),
+        ),
     );
 }
 
@@ -1003,7 +1041,7 @@ fn assoc_method(
 /// will include the const-stable version, but no stable version will be emitted, as a natural
 /// consequence of the above rules.
 fn render_stability_since_raw_with_extra(
-    w: &mut Buffer,
+    w: &mut String,
     stable_version: Option<StableSince>,
     const_stability: Option<ConstStability>,
     extra_class: &str,
@@ -1058,7 +1096,10 @@ fn render_stability_since_raw_with_extra(
     }
 
     if !stability.is_empty() {
-        write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#);
+        write_str(
+            w,
+            format_args!(r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#),
+        );
     }
 
     !stability.is_empty()
@@ -1074,7 +1115,7 @@ fn since_to_string(since: &StableSince) -> Option<String> {
 
 #[inline]
 fn render_stability_since_raw(
-    w: &mut Buffer,
+    w: &mut String,
     ver: Option<StableSince>,
     const_stability: Option<ConstStability>,
 ) -> bool {
@@ -1082,7 +1123,7 @@ fn render_stability_since_raw(
 }
 
 fn render_assoc_item(
-    w: &mut Buffer,
+    w: &mut String,
     item: &clean::Item,
     link: AssocItemLink<'_>,
     parent: ItemType,
@@ -1222,9 +1263,11 @@ pub(crate) fn render_all_impls(
     synthetic: &[&Impl],
     blanket_impl: &[&Impl],
 ) {
-    let mut impls = Buffer::html();
-    render_impls(cx, &mut impls, concrete, containing_item, true);
-    let impls = impls.into_inner();
+    let impls = {
+        let mut buf = String::new();
+        render_impls(cx, &mut buf, concrete, containing_item, true);
+        buf
+    };
     if !impls.is_empty() {
         write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations");
         write!(w, "<div id=\"trait-implementations-list\">{impls}</div>").unwrap();
@@ -1277,7 +1320,7 @@ fn render_assoc_items_inner(
     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
     if !non_trait.is_empty() {
         let mut close_tags = <Vec<&str>>::with_capacity(1);
-        let mut tmp_buf = Buffer::html();
+        let mut tmp_buf = String::new();
         let (render_mode, id, class_html) = match what {
             AssocItemRender::All => {
                 write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
@@ -1287,7 +1330,7 @@ fn render_assoc_items_inner(
                 let id =
                     cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
                 let derived_id = cx.derive_id(&id);
-                tmp_buf.write_str("<details class=\"toggle big-toggle\" open><summary>");
+                tmp_buf.push_str("<details class=\"toggle big-toggle\" open><summary>");
                 close_tags.push("</details>");
                 write_impl_section_heading(
                     &mut tmp_buf,
@@ -1298,14 +1341,14 @@ fn render_assoc_items_inner(
                     ),
                     &id,
                 );
-                tmp_buf.write_str("</summary>");
+                tmp_buf.push_str("</summary>");
                 if let Some(def_id) = type_.def_id(cx.cache()) {
                     cx.deref_id_map.borrow_mut().insert(def_id, id);
                 }
                 (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#)
             }
         };
-        let mut impls_buf = Buffer::html();
+        let mut impls_buf = String::new();
         for i in &non_trait {
             render_impl(
                 &mut impls_buf,
@@ -1325,13 +1368,7 @@ fn render_assoc_items_inner(
             );
         }
         if !impls_buf.is_empty() {
-            write!(
-                w,
-                "{}<div id=\"{id}\"{class_html}>{}</div>",
-                tmp_buf.into_inner(),
-                impls_buf.into_inner()
-            )
-            .unwrap();
+            write!(w, "{tmp_buf}<div id=\"{id}\"{class_html}>{impls_buf}</div>").unwrap();
             for tag in close_tags.into_iter().rev() {
                 w.write_str(tag).unwrap();
             }
@@ -1431,7 +1468,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
     }
 }
 
-pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<String> {
+pub(crate) fn notable_traits_button<'a, 'tcx>(
+    ty: &'a clean::Type,
+    cx: &'a Context<'tcx>,
+) -> Option<impl fmt::Display + 'a + Captures<'tcx>> {
     let mut has_notable_trait = false;
 
     if ty.is_unit() {
@@ -1473,19 +1513,20 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Optio
         }
     }
 
-    if has_notable_trait {
+    has_notable_trait.then(|| {
         cx.types_with_notable_traits.borrow_mut().insert(ty.clone());
-        Some(format!(
-            " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
-            ty = Escape(&format!("{:#}", ty.print(cx))),
-        ))
-    } else {
-        None
-    }
+        fmt::from_fn(|f| {
+            write!(
+                f,
+                " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
+                ty = Escape(&format!("{:#}", ty.print(cx))),
+            )
+        })
+    })
 }
 
 fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
-    let mut out = Buffer::html();
+    let mut out = String::new();
 
     let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
 
@@ -1507,15 +1548,20 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
 
             if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) {
                 if out.is_empty() {
-                    write!(
+                    write_str(
                         &mut out,
-                        "<h3>Notable traits for <code>{}</code></h3>\
-                     <pre><code>",
-                        impl_.for_.print(cx)
+                        format_args!(
+                            "<h3>Notable traits for <code>{}</code></h3>\
+                            <pre><code>",
+                            impl_.for_.print(cx)
+                        ),
                     );
                 }
 
-                write!(&mut out, "<div class=\"where\">{}</div>", impl_.print(false, cx));
+                write_str(
+                    &mut out,
+                    format_args!("<div class=\"where\">{}</div>", impl_.print(false, cx)),
+                );
                 for it in &impl_.items {
                     if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
                         out.push_str("<div class=\"where\">    ");
@@ -1538,10 +1584,10 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
         }
     }
     if out.is_empty() {
-        out.write_str("</code></pre>");
+        out.push_str("</code></pre>");
     }
 
-    (format!("{:#}", ty.print(cx)), out.into_inner())
+    (format!("{:#}", ty.print(cx)), out)
 }
 
 pub(crate) fn notable_traits_json<'a>(
@@ -1577,7 +1623,7 @@ struct ImplRenderingParameters {
 }
 
 fn render_impl(
-    w: &mut Buffer,
+    w: &mut String,
     cx: &Context<'_>,
     i: &Impl,
     parent: &clean::Item,
@@ -1598,8 +1644,8 @@ fn render_impl(
     // `containing_item` is used for rendering stability info. If the parent is a trait impl,
     // `containing_item` will the grandparent, since trait impls can't have stability attached.
     fn doc_impl_item(
-        boring: &mut Buffer,
-        interesting: &mut Buffer,
+        boring: &mut String,
+        interesting: &mut String,
         cx: &Context<'_>,
         item: &clean::Item,
         parent: &clean::Item,
@@ -1622,8 +1668,8 @@ fn render_impl(
 
         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
 
-        let mut doc_buffer = Buffer::empty_from(boring);
-        let mut info_buffer = Buffer::empty_from(boring);
+        let mut doc_buffer = String::new();
+        let mut info_buffer = String::new();
         let mut short_documented = true;
 
         if render_method_item {
@@ -1638,25 +1684,26 @@ fn render_impl(
                             document_item_info(cx, it, Some(parent))
                                 .render_into(&mut info_buffer)
                                 .unwrap();
-                            write!(
+                            write_str(
                                 &mut doc_buffer,
-                                "{}",
-                                document_full(item, cx, HeadingOffset::H5)
+                                format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
                             );
                             short_documented = false;
                         } else {
                             // In case the item isn't documented,
                             // provide short documentation from the trait.
-                            write!(
+                            write_str(
                                 &mut doc_buffer,
-                                "{}",
-                                document_short(
-                                    it,
-                                    cx,
-                                    link,
-                                    parent,
-                                    rendering_params.show_def_docs,
-                                )
+                                format_args!(
+                                    "{}",
+                                    document_short(
+                                        it,
+                                        cx,
+                                        link,
+                                        parent,
+                                        rendering_params.show_def_docs,
+                                    )
+                                ),
                             );
                         }
                     }
@@ -1665,15 +1712,20 @@ fn render_impl(
                         .render_into(&mut info_buffer)
                         .unwrap();
                     if rendering_params.show_def_docs {
-                        write!(&mut doc_buffer, "{}", document_full(item, cx, HeadingOffset::H5));
+                        write_str(
+                            &mut doc_buffer,
+                            format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
+                        );
                         short_documented = false;
                     }
                 }
             } else {
-                write!(
+                write_str(
                     &mut doc_buffer,
-                    "{}",
-                    document_short(item, cx, link, parent, rendering_params.show_def_docs)
+                    format_args!(
+                        "{}",
+                        document_short(item, cx, link, parent, rendering_params.show_def_docs)
+                    ),
                 );
             }
         }
@@ -1682,7 +1734,10 @@ fn render_impl(
         let toggled = !doc_buffer.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
+            write_str(
+                w,
+                format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
+            );
         }
         match &item.kind {
             clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
@@ -1697,13 +1752,16 @@ fn render_impl(
                                 .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
                         })
                         .map(|item| format!("{}.{name}", item.type_()));
-                    write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
+                    write_str(
+                        w,
+                        format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
+                    );
                     render_rightside(w, cx, item, render_mode);
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
+                        write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
                     }
-                    w.write_str("<h4 class=\"code-header\">");
+                    w.push_str("<h4 class=\"code-header\">");
                     render_assoc_item(
                         w,
                         item,
@@ -1712,19 +1770,22 @@ fn render_impl(
                         cx,
                         render_mode,
                     );
-                    w.write_str("</h4></section>");
+                    w.push_str("</h4></section>");
                 }
             }
             clean::RequiredAssocConstItem(ref generics, ref ty) => {
                 let source_id = format!("{item_type}.{name}");
                 let id = cx.derive_id(&source_id);
-                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
+                write_str(
+                    w,
+                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
+                );
                 render_rightside(w, cx, item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
+                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
                 }
-                w.write_str("<h4 class=\"code-header\">");
+                w.push_str("<h4 class=\"code-header\">");
                 assoc_const(
                     w,
                     item,
@@ -1735,18 +1796,21 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4></section>");
+                w.push_str("</h4></section>");
             }
             clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
                 let source_id = format!("{item_type}.{name}");
                 let id = cx.derive_id(&source_id);
-                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
+                write_str(
+                    w,
+                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
+                );
                 render_rightside(w, cx, item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
+                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
                 }
-                w.write_str("<h4 class=\"code-header\">");
+                w.push_str("<h4 class=\"code-header\">");
                 assoc_const(
                     w,
                     item,
@@ -1761,18 +1825,21 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4></section>");
+                w.push_str("</h4></section>");
             }
             clean::RequiredAssocTypeItem(ref generics, ref bounds) => {
                 let source_id = format!("{item_type}.{name}");
                 let id = cx.derive_id(&source_id);
-                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
+                write_str(
+                    w,
+                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
+                );
                 render_rightside(w, cx, item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
+                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
                 }
-                w.write_str("<h4 class=\"code-header\">");
+                w.push_str("<h4 class=\"code-header\">");
                 assoc_type(
                     w,
                     item,
@@ -1783,18 +1850,21 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4></section>");
+                w.push_str("</h4></section>");
             }
             clean::AssocTypeItem(tydef, _bounds) => {
                 let source_id = format!("{item_type}.{name}");
                 let id = cx.derive_id(&source_id);
-                write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
+                write_str(
+                    w,
+                    format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
+                );
                 render_rightside(w, cx, item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
+                    write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
                 }
-                w.write_str("<h4 class=\"code-header\">");
+                w.push_str("<h4 class=\"code-header\">");
                 assoc_type(
                     w,
                     item,
@@ -1805,22 +1875,22 @@ fn render_impl(
                     0,
                     cx,
                 );
-                w.write_str("</h4></section>");
+                w.push_str("</h4></section>");
             }
             clean::StrippedItem(..) => return,
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
         }
 
-        w.push_buffer(info_buffer);
+        w.push_str(&info_buffer);
         if toggled {
-            w.write_str("</summary>");
-            w.push_buffer(doc_buffer);
+            w.push_str("</summary>");
+            w.push_str(&doc_buffer);
             w.push_str("</details>");
         }
     }
 
-    let mut impl_items = Buffer::empty_from(w);
-    let mut default_impl_items = Buffer::empty_from(w);
+    let mut impl_items = String::new();
+    let mut default_impl_items = String::new();
     let impl_ = i.inner_impl();
 
     // Impl items are grouped by kinds:
@@ -1894,8 +1964,8 @@ fn render_impl(
     }
 
     fn render_default_items(
-        boring: &mut Buffer,
-        interesting: &mut Buffer,
+        boring: &mut String,
+        interesting: &mut String,
         cx: &Context<'_>,
         t: &clean::Trait,
         i: &clean::Impl,
@@ -1960,11 +2030,13 @@ fn render_impl(
         let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
         if toggled {
             close_tags.push("</details>");
-            write!(
+            write_str(
                 w,
-                "<details class=\"toggle implementors-toggle\"{}>\
-                     <summary>",
-                if rendering_params.toggle_open_by_default { " open" } else { "" }
+                format_args!(
+                    "<details class=\"toggle implementors-toggle\"{}>\
+                        <summary>",
+                    if rendering_params.toggle_open_by_default { " open" } else { "" }
+                ),
             );
         }
 
@@ -1995,38 +2067,38 @@ fn render_impl(
             &before_dox,
         );
         if toggled {
-            w.write_str("</summary>");
+            w.push_str("</summary>");
         }
 
         if before_dox.is_some() {
             if trait_.is_none() && impl_.items.is_empty() {
-                w.write_str(
+                w.push_str(
                     "<div class=\"item-info\">\
                          <div class=\"stab empty-impl\">This impl block contains no items.</div>\
                      </div>",
                 );
             }
             if let Some(after_dox) = after_dox {
-                write!(w, "<div class=\"docblock\">{after_dox}</div>");
+                write_str(w, format_args!("<div class=\"docblock\">{after_dox}</div>"));
             }
         }
         if !default_impl_items.is_empty() || !impl_items.is_empty() {
-            w.write_str("<div class=\"impl-items\">");
+            w.push_str("<div class=\"impl-items\">");
             close_tags.push("</div>");
         }
     }
     if !default_impl_items.is_empty() || !impl_items.is_empty() {
-        w.push_buffer(default_impl_items);
-        w.push_buffer(impl_items);
+        w.push_str(&default_impl_items);
+        w.push_str(&impl_items);
     }
     for tag in close_tags.into_iter().rev() {
-        w.write_str(tag);
+        w.push_str(tag);
     }
 }
 
 // Render the items that appear on the right side of methods, impls, and
 // associated types. For example "1.0.0 (const: 1.39.0) · source".
-fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) {
+fn render_rightside(w: &mut String, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) {
     let tcx = cx.tcx();
 
     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
@@ -2038,7 +2110,7 @@ fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render
     let src_href = cx.src_href(item);
     let has_src_ref = src_href.is_some();
 
-    let mut rightside = Buffer::new();
+    let mut rightside = String::new();
     let has_stability = render_stability_since_raw_with_extra(
         &mut rightside,
         item.stable_since(tcx),
@@ -2047,20 +2119,26 @@ fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render
     );
     if let Some(link) = src_href {
         if has_stability {
-            write!(rightside, " · <a class=\"src\" href=\"{link}\">Source</a>")
+            write_str(
+                &mut rightside,
+                format_args!(" · <a class=\"src\" href=\"{link}\">Source</a>"),
+            );
         } else {
-            write!(rightside, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
+            write_str(
+                &mut rightside,
+                format_args!("<a class=\"src rightside\" href=\"{link}\">Source</a>"),
+            );
         }
     }
     if has_stability && has_src_ref {
-        write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
+        write_str(w, format_args!("<span class=\"rightside\">{rightside}</span>"));
     } else {
-        w.push_buffer(rightside);
+        w.push_str(&rightside);
     }
 }
 
 pub(crate) fn render_impl_summary(
-    w: &mut Buffer,
+    w: &mut String,
     cx: &Context<'_>,
     i: &Impl,
     parent: &clean::Item,
@@ -2073,25 +2151,27 @@ pub(crate) fn render_impl_summary(
 ) {
     let inner_impl = i.inner_impl();
     let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
-    let aliases = if aliases.is_empty() {
-        String::new()
-    } else {
-        format!(" data-aliases=\"{}\"", aliases.join(","))
-    };
-    write!(w, "<section id=\"{id}\" class=\"impl\"{aliases}>");
+    let aliases = (!aliases.is_empty())
+        .then_some(fmt::from_fn(|f| {
+            write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f)))
+        }))
+        .maybe_display();
+    write_str(w, format_args!("<section id=\"{id}\" class=\"impl\"{aliases}>"));
     render_rightside(w, cx, &i.impl_item, RenderMode::Normal);
-    write!(
+    write_str(
         w,
-        "<a href=\"#{id}\" class=\"anchor\">§</a>\
-         <h3 class=\"code-header\">"
+        format_args!(
+            "<a href=\"#{id}\" class=\"anchor\">§</a>\
+            <h3 class=\"code-header\">"
+        ),
     );
 
     if let Some(use_absolute) = use_absolute {
-        write!(w, "{}", inner_impl.print(use_absolute, cx));
+        write_str(w, format_args!("{}", inner_impl.print(use_absolute, cx)));
         if show_def_docs {
             for it in &inner_impl.items {
                 if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
-                    w.write_str("<div class=\"where\">  ");
+                    w.push_str("<div class=\"where\">  ");
                     assoc_type(
                         w,
                         it,
@@ -2102,30 +2182,32 @@ pub(crate) fn render_impl_summary(
                         0,
                         cx,
                     );
-                    w.write_str(";</div>");
+                    w.push_str(";</div>");
                 }
             }
         }
     } else {
-        write!(w, "{}", inner_impl.print(false, cx));
+        write_str(w, format_args!("{}", inner_impl.print(false, cx)));
     }
-    w.write_str("</h3>");
+    w.push_str("</h3>");
 
     let is_trait = inner_impl.trait_.is_some();
     if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
-        write!(
+        write_str(
             w,
-            "<span class=\"item-info\">\
+            format_args!(
+                "<span class=\"item-info\">\
                  <div class=\"stab portability\">{portability}</div>\
              </span>",
+            ),
         );
     }
 
     if let Some(doc) = doc {
-        write!(w, "<div class=\"docblock\">{doc}</div>");
+        write_str(w, format_args!("<div class=\"docblock\">{doc}</div>"));
     }
 
-    w.write_str("</section>");
+    w.push_str("</section>");
 }
 
 pub(crate) fn small_url_encode(s: String) -> String {
@@ -2577,7 +2659,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
             cx,
             &cx.root_path(),
             &highlight::DecorationInfo(decoration_info),
-            sources::SourceContext::Embedded(sources::ScrapedInfo {
+            &sources::SourceContext::Embedded(sources::ScrapedInfo {
                 needs_expansion,
                 offset: line_min,
                 name: &call_data.display_name,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 4f51b7a0108..f3201147039 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1,8 +1,7 @@
 use std::cmp::Ordering;
 use std::fmt;
-use std::fmt::{Display, Write};
+use std::fmt::Display;
 
-use itertools::Itertools;
 use rinja::Template;
 use rustc_abi::VariantIdx;
 use rustc_data_structures::captures::Captures;
@@ -27,17 +26,17 @@ use super::{
 };
 use crate::clean;
 use crate::config::ModuleSorting;
+use crate::display::{Joined as _, MaybeDisplay as _};
 use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
 use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
 use crate::html::format::{
-    Buffer, Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
-    print_constness_with_space, print_where_clause, visibility_print_with_space,
+    Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
+    print_constness_with_space, print_where_clause, visibility_print_with_space, write_str,
 };
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
-use crate::joined::Joined as _;
 
 /// Generates a Rinja template struct for rendering items with common methods.
 ///
@@ -165,16 +164,16 @@ struct ItemVars<'a> {
 
 /// Calls `print_where_clause` and returns `true` if a `where` clause was generated.
 fn print_where_clause_and_check<'a, 'tcx: 'a>(
-    buffer: &mut Buffer,
+    buffer: &mut String,
     gens: &'a clean::Generics,
     cx: &'a Context<'tcx>,
 ) -> bool {
     let len_before = buffer.len();
-    write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline));
+    write_str(buffer, format_args!("{}", print_where_clause(gens, cx, 0, Ending::Newline)));
     len_before != buffer.len()
 }
 
-pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
+pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut String) {
     debug_assert!(!item.is_stripped());
     let typ = match item.kind {
         clean::ModuleItem(_) => {
@@ -207,13 +206,15 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
             unreachable!();
         }
     };
-    let mut stability_since_raw = Buffer::new();
-    render_stability_since_raw(
-        &mut stability_since_raw,
-        item.stable_since(cx.tcx()),
-        item.const_stability(cx.tcx()),
-    );
-    let stability_since_raw: String = stability_since_raw.into_inner();
+    let stability_since_raw = {
+        let mut buf = String::new();
+        render_stability_since_raw(
+            &mut buf,
+            item.stable_since(cx.tcx()),
+            item.const_stability(cx.tcx()),
+        );
+        buf
+    };
 
     // Write source tag
     //
@@ -278,10 +279,12 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
     // Render notable-traits.js used for all methods in this module.
     let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut();
     if !types_with_notable_traits.is_empty() {
-        write!(
+        write_str(
             buf,
-            r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
-            notable_traits_json(types_with_notable_traits.iter(), cx)
+            format_args!(
+                r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
+                notable_traits_json(types_with_notable_traits.iter(), cx)
+            ),
         );
         types_with_notable_traits.clear();
     }
@@ -311,8 +314,8 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display {
     fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>);
 }
 
-fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
-    write!(w, "{}", document(cx, item, None, HeadingOffset::H2));
+fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
+    write_str(w, format_args!("{}", document(cx, item, None, HeadingOffset::H2)));
 
     let mut not_stripped_items =
         items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
@@ -398,7 +401,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
         let my_section = item_ty_to_section(myitem.type_());
         if Some(my_section) != last_section {
             if last_section.is_some() {
-                w.write_str(ITEM_TABLE_CLOSE);
+                w.push_str(ITEM_TABLE_CLOSE);
             }
             last_section = Some(my_section);
             let section_id = my_section.id();
@@ -412,21 +415,29 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                 use crate::html::format::anchor;
 
                 match *src {
-                    Some(src) => write!(
-                        w,
-                        "<dt><code>{}extern crate {} as {};",
-                        visibility_print_with_space(myitem, cx),
-                        anchor(myitem.item_id.expect_def_id(), src, cx),
-                        EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
-                    ),
-                    None => write!(
-                        w,
-                        "<dt><code>{}extern crate {};",
-                        visibility_print_with_space(myitem, cx),
-                        anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
-                    ),
+                    Some(src) => {
+                        write_str(
+                            w,
+                            format_args!(
+                                "<dt><code>{}extern crate {} as {};",
+                                visibility_print_with_space(myitem, cx),
+                                anchor(myitem.item_id.expect_def_id(), src, cx),
+                                EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
+                            ),
+                        );
+                    }
+                    None => {
+                        write_str(
+                            w,
+                            format_args!(
+                                "<dt><code>{}extern crate {};",
+                                visibility_print_with_space(myitem, cx),
+                                anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx)
+                            ),
+                        );
+                    }
                 }
-                w.write_str("</code></dt>");
+                w.push_str("</code></dt>");
             }
 
             clean::ImportItem(ref import) => {
@@ -440,13 +451,15 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     }
                     clean::ImportKind::Glob => String::new(),
                 };
-                write!(
+                write_str(
                     w,
-                    "<dt{id}>\
-                         <code>{vis}{imp}</code>{stab_tags}\
-                     </dt>",
-                    vis = visibility_print_with_space(myitem, cx),
-                    imp = import.print(cx),
+                    format_args!(
+                        "<dt{id}>\
+                            <code>{vis}{imp}</code>{stab_tags}\
+                        </dt>",
+                        vis = visibility_print_with_space(myitem, cx),
+                        imp = import.print(cx)
+                    ),
                 );
             }
 
@@ -484,33 +497,31 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
                     MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
                 let (docs_before, docs_after) =
                     if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
-                write!(
+                write_str(
                     w,
-                    "<dt>\
-                        <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
-                        {visibility_and_hidden}\
-                        {unsafety_flag}\
-                        {stab_tags}\
-                     </dt>\
-                     {docs_before}{docs}{docs_after}",
-                    name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
-                    visibility_and_hidden = visibility_and_hidden,
-                    stab_tags = extra_info_tags(tcx, myitem, item, None),
-                    class = myitem.type_(),
-                    unsafety_flag = unsafety_flag,
-                    href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
-                    title = [myitem.type_().to_string(), full_path(cx, myitem)]
-                        .iter()
-                        .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
-                        .collect::<Vec<_>>()
-                        .join(" "),
+                    format_args!(
+                        "<dt>\
+                            <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
+                            {visibility_and_hidden}\
+                            {unsafety_flag}\
+                            {stab_tags}\
+                        </dt>\
+                        {docs_before}{docs}{docs_after}",
+                        name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
+                        visibility_and_hidden = visibility_and_hidden,
+                        stab_tags = extra_info_tags(tcx, myitem, item, None),
+                        class = myitem.type_(),
+                        unsafety_flag = unsafety_flag,
+                        href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
+                        title = format_args!("{} {}", myitem.type_(), full_path(cx, myitem)),
+                    ),
                 );
             }
         }
     }
 
     if last_section.is_some() {
-        w.write_str(ITEM_TABLE_CLOSE);
+        w.push_str(ITEM_TABLE_CLOSE);
     }
 }
 
@@ -572,7 +583,7 @@ fn extra_info_tags<'a, 'tcx: 'a>(
     })
 }
 
-fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
+fn item_function(w: &mut String, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
     let tcx = cx.tcx();
     let header = it.fn_header(tcx).expect("printing a function which isn't a function");
     debug!(
@@ -603,31 +614,32 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
         + name.as_str().len()
         + generics_len;
 
-    let notable_traits = notable_traits_button(&f.decl.output, cx);
+    let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display();
 
     wrap_item(w, |w| {
         w.reserve(header_len);
-        write!(
+        write_str(
             w,
-            "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
+            format_args!(
+                "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
                 {name}{generics}{decl}{notable_traits}{where_clause}",
-            attrs = render_attributes_in_pre(it, "", cx),
-            vis = visibility,
-            constness = constness,
-            asyncness = asyncness,
-            safety = safety,
-            abi = abi,
-            name = name,
-            generics = f.generics.print(cx),
-            where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
-            decl = f.decl.full_print(header_len, 0, cx),
-            notable_traits = notable_traits.unwrap_or_default(),
+                attrs = render_attributes_in_pre(it, "", cx),
+                vis = visibility,
+                constness = constness,
+                asyncness = asyncness,
+                safety = safety,
+                abi = abi,
+                name = name,
+                generics = f.generics.print(cx),
+                where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
+                decl = f.decl.full_print(header_len, 0, cx),
+            ),
         );
     });
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 }
 
-fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
+fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
     let tcx = cx.tcx();
     let bounds = bounds(&t.bounds, false, cx);
     let required_types =
@@ -645,28 +657,33 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
 
     // Output the trait definition
     wrap_item(w, |mut w| {
-        write!(
+        write_str(
             w,
-            "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
-            attrs = render_attributes_in_pre(it, "", cx),
-            vis = visibility_print_with_space(it, cx),
-            safety = t.safety(tcx).print_with_space(),
-            is_auto = if t.is_auto(tcx) { "auto " } else { "" },
-            name = it.name.unwrap(),
-            generics = t.generics.print(cx),
+            format_args!(
+                "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
+                attrs = render_attributes_in_pre(it, "", cx),
+                vis = visibility_print_with_space(it, cx),
+                safety = t.safety(tcx).print_with_space(),
+                is_auto = if t.is_auto(tcx) { "auto " } else { "" },
+                name = it.name.unwrap(),
+                generics = t.generics.print(cx),
+            ),
         );
 
         if !t.generics.where_predicates.is_empty() {
-            write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
+            write_str(
+                w,
+                format_args!("{}", print_where_clause(&t.generics, cx, 0, Ending::Newline)),
+            );
         } else {
-            w.write_str(" ");
+            w.push_str(" ");
         }
 
         if t.items.is_empty() {
-            w.write_str("{ }");
+            w.push_str("{ }");
         } else {
             // FIXME: we should be using a derived_id for the Anchors here
-            w.write_str("{\n");
+            w.push_str("{\n");
             let mut toggle = false;
 
             // If there are too many associated types, hide _everything_
@@ -687,7 +704,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                         cx,
                         RenderMode::Normal,
                     );
-                    w.write_str(";\n");
+                    w.push_str(";\n");
                 }
             }
             // If there are too many associated constants, hide everything after them
@@ -707,7 +724,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 );
             }
             if count_types != 0 && (count_consts != 0 || count_methods != 0) {
-                w.write_str("\n");
+                w.push_str("\n");
             }
             for consts in [&required_consts, &provided_consts] {
                 for c in consts {
@@ -719,7 +736,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                         cx,
                         RenderMode::Normal,
                     );
-                    w.write_str(";\n");
+                    w.push_str(";\n");
                 }
             }
             if !toggle && should_hide_fields(count_methods) {
@@ -727,11 +744,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 toggle_open(&mut w, format_args!("{count_methods} methods"));
             }
             if count_consts != 0 && count_methods != 0 {
-                w.write_str("\n");
+                w.push_str("\n");
             }
 
             if !required_methods.is_empty() {
-                writeln!(w, "    // Required method{}", pluralize(required_methods.len()));
+                write_str(
+                    w,
+                    format_args_nl!("    // Required method{}", pluralize(required_methods.len())),
+                );
             }
             for (pos, m) in required_methods.iter().enumerate() {
                 render_assoc_item(
@@ -742,18 +762,21 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                     cx,
                     RenderMode::Normal,
                 );
-                w.write_str(";\n");
+                w.push_str(";\n");
 
                 if pos < required_methods.len() - 1 {
-                    w.write_str("<span class=\"item-spacer\"></span>");
+                    w.push_str("<span class=\"item-spacer\"></span>");
                 }
             }
             if !required_methods.is_empty() && !provided_methods.is_empty() {
-                w.write_str("\n");
+                w.push_str("\n");
             }
 
             if !provided_methods.is_empty() {
-                writeln!(w, "    // Provided method{}", pluralize(provided_methods.len()));
+                write_str(
+                    w,
+                    format_args_nl!("    // Provided method{}", pluralize(provided_methods.len())),
+                );
             }
             for (pos, m) in provided_methods.iter().enumerate() {
                 render_assoc_item(
@@ -765,39 +788,42 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                     RenderMode::Normal,
                 );
 
-                w.write_str(" { ... }\n");
+                w.push_str(" { ... }\n");
 
                 if pos < provided_methods.len() - 1 {
-                    w.write_str("<span class=\"item-spacer\"></span>");
+                    w.push_str("<span class=\"item-spacer\"></span>");
                 }
             }
             if toggle {
                 toggle_close(&mut w);
             }
-            w.write_str("}");
+            w.push_str("}");
         }
     });
 
     // Trait documentation
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 
-    fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
+    fn trait_item(w: &mut String, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
         let name = m.name.unwrap();
         info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
         let item_type = m.type_();
         let id = cx.derive_id(format!("{item_type}.{name}"));
 
-        let mut content = Buffer::empty_from(w);
-        write!(content, "{}", document_full(m, cx, HeadingOffset::H5));
+        let mut content = String::new();
+        write_str(&mut content, format_args!("{}", document_full(m, cx, HeadingOffset::H5)));
 
         let toggled = !content.is_empty();
         if toggled {
             let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
-            write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
+            write_str(
+                w,
+                format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
+            );
         }
-        write!(w, "<section id=\"{id}\" class=\"method\">");
+        write_str(w, format_args!("<section id=\"{id}\" class=\"method\">"));
         render_rightside(w, cx, m, RenderMode::Normal);
-        write!(w, "<h4 class=\"code-header\">");
+        write_str(w, format_args!("<h4 class=\"code-header\">"));
         render_assoc_item(
             w,
             m,
@@ -806,12 +832,12 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
             cx,
             RenderMode::Normal,
         );
-        w.write_str("</h4></section>");
+        w.push_str("</h4></section>");
         document_item_info(cx, m, Some(t)).render_into(w).unwrap();
         if toggled {
-            write!(w, "</summary>");
-            w.push_buffer(content);
-            write!(w, "</details>");
+            write_str(w, format_args!("</summary>"));
+            w.push_str(&content);
+            write_str(w, format_args!("</details>"));
         }
     }
 
@@ -826,7 +852,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         for t in required_consts {
             trait_item(w, cx, t, it);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
     }
     if !provided_consts.is_empty() {
         write_section_heading(
@@ -839,7 +865,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         for t in provided_consts {
             trait_item(w, cx, t, it);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
     }
 
     if !required_types.is_empty() {
@@ -853,7 +879,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         for t in required_types {
             trait_item(w, cx, t, it);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
     }
     if !provided_types.is_empty() {
         write_section_heading(
@@ -866,7 +892,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         for t in provided_types {
             trait_item(w, cx, t, it);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
     }
 
     // Output the documentation for each function individually
@@ -880,17 +906,19 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         );
 
         if let Some(list) = must_implement_one_of_functions.as_deref() {
-            write!(
+            write_str(
                 w,
-                "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
-                list.iter().join("`, `")
+                format_args!(
+                    "<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
+                    fmt::from_fn(|f| list.iter().joined("`, `", f))
+                ),
             );
         }
 
         for m in required_methods {
             trait_item(w, cx, m, it);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
     }
     if !provided_methods.is_empty() {
         write_section_heading(
@@ -903,11 +931,17 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         for m in provided_methods {
             trait_item(w, cx, m, it);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
     }
 
     // If there are methods directly on this trait object, render them here.
-    write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All));
+    write_str(
+        w,
+        format_args!(
+            "{}",
+            render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
+        ),
+    );
 
     let mut extern_crates = FxIndexSet::default();
 
@@ -997,7 +1031,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         for implementor in concrete {
             render_implementor(cx, implementor, it, w, &implementor_dups, &[]);
         }
-        w.write_str("</div>");
+        w.push_str("</div>");
 
         if t.is_auto(tcx) {
             write_section_heading(
@@ -1020,7 +1054,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                     ),
                 );
             }
-            w.write_str("</div>");
+            w.push_str("</div>");
         }
     } else {
         // even without any implementations to write in, we still want the heading and list, so the
@@ -1129,17 +1163,20 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         js_src_path.extend(cx.current.iter().copied());
         js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap()));
     }
-    let extern_crates = extern_crates
-        .into_iter()
-        .map(|cnum| tcx.crate_name(cnum).to_string())
-        .collect::<Vec<_>>()
-        .join(",");
-    let (extern_before, extern_after) =
-        if extern_crates.is_empty() { ("", "") } else { (" data-ignore-extern-crates=\"", "\"") };
-    write!(
+    let extern_crates = fmt::from_fn(|f| {
+        if !extern_crates.is_empty() {
+            f.write_str(" data-ignore-extern-crates=\"")?;
+            extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?;
+            f.write_str("\"")?;
+        }
+        Ok(())
+    });
+    write_str(
         w,
-        "<script src=\"{src}\"{extern_before}{extern_crates}{extern_after} async></script>",
-        src = js_src_path.finish(),
+        format_args!(
+            "<script src=\"{src}\"{extern_crates} async></script>",
+            src = js_src_path.finish()
+        ),
     );
 }
 
@@ -1171,21 +1208,23 @@ fn item_trait_alias(
         .unwrap();
 }
 
-fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) {
+fn item_type_alias(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) {
     wrap_item(w, |w| {
-        write!(
+        write_str(
             w,
-            "{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
-            attrs = render_attributes_in_pre(it, "", cx),
-            vis = visibility_print_with_space(it, cx),
-            name = it.name.unwrap(),
-            generics = t.generics.print(cx),
-            where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
-            type_ = t.type_.print(cx),
+            format_args!(
+                "{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
+                attrs = render_attributes_in_pre(it, "", cx),
+                vis = visibility_print_with_space(it, cx),
+                name = it.name.unwrap(),
+                generics = t.generics.print(cx),
+                where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
+                type_ = t.type_.print(cx),
+            ),
         );
     });
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 
     if let Some(inner_type) = &t.inner_type {
         write_section_heading(w, "Aliased Type", "aliased-type", None, "");
@@ -1201,7 +1240,7 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
                     let variants_count = variants_iter().count();
                     let has_stripped_entries = variants_len != variants_count;
 
-                    write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx));
+                    write_str(w, format_args!("enum {}{}", it.name.unwrap(), t.generics.print(cx)));
                     render_enum_fields(
                         w,
                         cx,
@@ -1220,7 +1259,10 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
                     let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
                     let has_stripped_fields = fields.len() != fields_count;
 
-                    write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx));
+                    write_str(
+                        w,
+                        format_args!("union {}{}", it.name.unwrap(), t.generics.print(cx)),
+                    );
                     render_struct_fields(
                         w,
                         Some(&t.generics),
@@ -1239,7 +1281,10 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
                     let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
                     let has_stripped_fields = fields.len() != fields_count;
 
-                    write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx));
+                    write_str(
+                        w,
+                        format_args!("struct {}{}", it.name.unwrap(), t.generics.print(cx)),
+                    );
                     render_struct_fields(
                         w,
                         Some(&t.generics),
@@ -1261,8 +1306,8 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
     // won't be visible anywhere in the docs. It would be nice to also show
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
-    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
-    write!(w, "{}", document_type_layout(cx, def_id));
+    write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
+    write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
 
     // [RUSTDOCIMPL] type.impl
     //
@@ -1351,16 +1396,18 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
             .collect();
         js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
         js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
-        let self_path = self_fqp.iter().map(Symbol::as_str).collect::<Vec<&str>>().join("::");
-        write!(
+        let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f));
+        write_str(
             w,
-            "<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>",
-            src = js_src_path.finish(),
+            format_args!(
+                "<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>",
+                src = js_src_path.finish()
+            ),
         );
     }
 }
 
-fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
+fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
     item_template!(
         #[template(path = "item_union.html")]
         struct ItemUnion<'a, 'cx> {
@@ -1445,16 +1492,18 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
     })
 }
 
-fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
+fn item_enum(w: &mut String, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
     let count_variants = e.variants().count();
     wrap_item(w, |w| {
         render_attributes_in_code(w, it, cx);
-        write!(
+        write_str(
             w,
-            "{}enum {}{}",
-            visibility_print_with_space(it, cx),
-            it.name.unwrap(),
-            e.generics.print(cx),
+            format_args!(
+                "{}enum {}{}",
+                visibility_print_with_space(it, cx),
+                it.name.unwrap(),
+                e.generics.print(cx),
+            ),
         );
 
         render_enum_fields(
@@ -1469,14 +1518,14 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
         );
     });
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 
     if count_variants != 0 {
         item_variants(w, cx, it, &e.variants, it.def_id().unwrap());
     }
     let def_id = it.item_id.expect_def_id();
-    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
-    write!(w, "{}", document_type_layout(cx, def_id));
+    write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
+    write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
 }
 
 /// It'll return false if any variant is not a C-like variant. Otherwise it'll return true if at
@@ -1505,7 +1554,7 @@ fn should_show_enum_discriminant(
 }
 
 fn display_c_like_variant(
-    w: &mut Buffer,
+    w: &mut String,
     cx: &Context<'_>,
     item: &clean::Item,
     variant: &clean::Variant,
@@ -1515,22 +1564,22 @@ fn display_c_like_variant(
 ) {
     let name = item.name.unwrap();
     if let Some(ref value) = variant.discriminant {
-        write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true));
+        write_str(w, format_args!("{} = {}", name.as_str(), value.value(cx.tcx(), true)));
     } else if should_show_enum_discriminant {
         let adt_def = cx.tcx().adt_def(enum_def_id);
         let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
         if discr.ty.is_signed() {
-            write!(w, "{} = {}", name.as_str(), discr.val as i128);
+            write_str(w, format_args!("{} = {}", name.as_str(), discr.val as i128));
         } else {
-            write!(w, "{} = {}", name.as_str(), discr.val);
+            write_str(w, format_args!("{} = {}", name.as_str(), discr.val));
         }
     } else {
-        w.write_str(name.as_str());
+        w.push_str(name.as_str());
     }
 }
 
 fn render_enum_fields(
-    mut w: &mut Buffer,
+    mut w: &mut String,
     cx: &Context<'_>,
     g: Option<&clean::Generics>,
     variants: &IndexVec<VariantIdx, clean::Item>,
@@ -1542,14 +1591,14 @@ fn render_enum_fields(
     let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants);
     if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) {
         // If there wasn't a `where` clause, we add a whitespace.
-        w.write_str(" ");
+        w.push_str(" ");
     }
 
     let variants_stripped = has_stripped_entries;
     if count_variants == 0 && !variants_stripped {
-        w.write_str("{}");
+        w.push_str("{}");
     } else {
-        w.write_str("{\n");
+        w.push_str("{\n");
         let toggle = should_hide_fields(count_variants);
         if toggle {
             toggle_open(&mut w, format_args!("{count_variants} variants"));
@@ -1559,7 +1608,7 @@ fn render_enum_fields(
             if v.is_stripped() {
                 continue;
             }
-            w.write_str(TAB);
+            w.push_str(TAB);
             match v.kind {
                 clean::VariantItem(ref var) => match var.kind {
                     clean::VariantKind::CLike => display_c_like_variant(
@@ -1572,7 +1621,14 @@ fn render_enum_fields(
                         enum_def_id,
                     ),
                     clean::VariantKind::Tuple(ref s) => {
-                        write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s));
+                        write_str(
+                            w,
+                            format_args!(
+                                "{}({})",
+                                v.name.unwrap(),
+                                print_tuple_struct_fields(cx, s)
+                            ),
+                        );
                     }
                     clean::VariantKind::Struct(ref s) => {
                         render_struct(w, v, None, None, &s.fields, TAB, false, cx);
@@ -1580,21 +1636,21 @@ fn render_enum_fields(
                 },
                 _ => unreachable!(),
             }
-            w.write_str(",\n");
+            w.push_str(",\n");
         }
 
         if variants_stripped && !is_non_exhaustive {
-            w.write_str("    <span class=\"comment\">// some variants omitted</span>\n");
+            w.push_str("    <span class=\"comment\">// some variants omitted</span>\n");
         }
         if toggle {
             toggle_close(&mut w);
         }
-        w.write_str("}");
+        w.push_str("}");
     }
 }
 
 fn item_variants(
-    w: &mut Buffer,
+    w: &mut String,
     cx: &Context<'_>,
     it: &clean::Item,
     variants: &IndexVec<VariantIdx, clean::Item>,
@@ -1615,10 +1671,12 @@ fn item_variants(
             continue;
         }
         let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
-        write!(
+        write_str(
             w,
-            "<section id=\"{id}\" class=\"variant\">\
-                <a href=\"#{id}\" class=\"anchor\">§</a>",
+            format_args!(
+                "<section id=\"{id}\" class=\"variant\">\
+                <a href=\"#{id}\" class=\"anchor\">§</a>"
+            ),
         );
         render_stability_since_raw_with_extra(
             w,
@@ -1626,7 +1684,7 @@ fn item_variants(
             variant.const_stability(tcx),
             " rightside",
         );
-        w.write_str("<h3 class=\"code-header\">");
+        w.push_str("<h3 class=\"code-header\">");
         if let clean::VariantItem(ref var) = variant.kind
             && let clean::VariantKind::CLike = var.kind
         {
@@ -1640,17 +1698,17 @@ fn item_variants(
                 enum_def_id,
             );
         } else {
-            w.write_str(variant.name.unwrap().as_str());
+            w.push_str(variant.name.unwrap().as_str());
         }
 
         let clean::VariantItem(variant_data) = &variant.kind else { unreachable!() };
 
         if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
-            write!(w, "({})", print_tuple_struct_fields(cx, s));
+            write_str(w, format_args!("({})", print_tuple_struct_fields(cx, s)));
         }
-        w.write_str("</h3></section>");
+        w.push_str("</h3></section>");
 
-        write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4));
+        write_str(w, format_args!("{}", document(cx, variant, Some(it), HeadingOffset::H4)));
 
         let heading_and_fields = match &variant_data.kind {
             clean::VariantKind::Struct(s) => {
@@ -1676,12 +1734,14 @@ fn item_variants(
         if let Some((heading, fields)) = heading_and_fields {
             let variant_id =
                 cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
-            write!(
+            write_str(
                 w,
-                "<div class=\"sub-variant\" id=\"{variant_id}\">\
-                    <h4>{heading}</h4>\
-                    {}",
-                document_non_exhaustive(variant)
+                format_args!(
+                    "<div class=\"sub-variant\" id=\"{variant_id}\">\
+                        <h4>{heading}</h4>\
+                        {}",
+                    document_non_exhaustive(variant)
+                ),
             );
             for field in fields {
                 match field.kind {
@@ -1692,40 +1752,44 @@ fn item_variants(
                             variant.name.unwrap(),
                             field.name.unwrap()
                         ));
-                        write!(
+                        write_str(
                             w,
-                            "<div class=\"sub-variant-field\">\
-                                 <span id=\"{id}\" class=\"section-header\">\
-                                     <a href=\"#{id}\" class=\"anchor field\">§</a>\
-                                     <code>{f}: {t}</code>\
-                                 </span>",
-                            f = field.name.unwrap(),
-                            t = ty.print(cx),
+                            format_args!(
+                                "<div class=\"sub-variant-field\">\
+                                    <span id=\"{id}\" class=\"section-header\">\
+                                        <a href=\"#{id}\" class=\"anchor field\">§</a>\
+                                        <code>{f}: {t}</code>\
+                                    </span>",
+                                f = field.name.unwrap(),
+                                t = ty.print(cx),
+                            ),
                         );
-                        write!(
+                        write_str(
                             w,
-                            "{}</div>",
-                            document(cx, field, Some(variant), HeadingOffset::H5)
+                            format_args!(
+                                "{}</div>",
+                                document(cx, field, Some(variant), HeadingOffset::H5),
+                            ),
                         );
                     }
                     _ => unreachable!(),
                 }
             }
-            w.write_str("</div>");
+            w.push_str("</div>");
         }
     }
-    write!(w, "</div>");
+    write_str(w, format_args!("</div>"));
 }
 
-fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
+fn item_macro(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
     wrap_item(w, |w| {
         // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
         if !t.macro_rules {
-            write!(w, "{}", visibility_print_with_space(it, cx));
+            write_str(w, format_args!("{}", visibility_print_with_space(it, cx)));
         }
-        write!(w, "{}", Escape(&t.source));
+        write_str(w, format_args!("{}", Escape(&t.source)));
     });
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 }
 
 fn item_proc_macro(
@@ -1779,7 +1843,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) {
 }
 
 fn item_constant(
-    w: &mut Buffer,
+    w: &mut String,
     cx: &Context<'_>,
     it: &clean::Item,
     generics: &clean::Generics,
@@ -1790,14 +1854,16 @@ fn item_constant(
         let tcx = cx.tcx();
         render_attributes_in_code(w, it, cx);
 
-        write!(
+        write_str(
             w,
-            "{vis}const {name}{generics}: {typ}{where_clause}",
-            vis = visibility_print_with_space(it, cx),
-            name = it.name.unwrap(),
-            generics = generics.print(cx),
-            typ = ty.print(cx),
-            where_clause = print_where_clause(generics, cx, 0, Ending::NoNewline),
+            format_args!(
+                "{vis}const {name}{generics}: {typ}{where_clause}",
+                vis = visibility_print_with_space(it, cx),
+                name = it.name.unwrap(),
+                generics = generics.print(cx),
+                typ = ty.print(cx),
+                where_clause = print_where_clause(generics, cx, 0, Ending::NoNewline)
+            ),
         );
 
         // FIXME: The code below now prints
@@ -1813,9 +1879,9 @@ fn item_constant(
         let is_literal = c.is_literal(tcx);
         let expr = c.expr(tcx);
         if value.is_some() || is_literal {
-            write!(w, " = {expr};", expr = Escape(&expr));
+            write_str(w, format_args!(" = {expr};", expr = Escape(&expr)));
         } else {
-            w.write_str(";");
+            w.push_str(";");
         }
 
         if !is_literal {
@@ -1826,32 +1892,32 @@ fn item_constant(
                 if value_lowercase != expr_lowercase
                     && value_lowercase.trim_end_matches("i32") != expr_lowercase
                 {
-                    write!(w, " // {value}", value = Escape(value));
+                    write_str(w, format_args!(" // {value}", value = Escape(value)));
                 }
             }
         }
     });
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 }
 
-fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
+fn item_struct(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
     wrap_item(w, |w| {
         render_attributes_in_code(w, it, cx);
         render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
     });
 
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 
     item_fields(w, cx, it, &s.fields, s.ctor_kind);
 
     let def_id = it.item_id.expect_def_id();
-    write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
-    write!(w, "{}", document_type_layout(cx, def_id));
+    write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
+    write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
 }
 
 fn item_fields(
-    w: &mut Buffer,
+    w: &mut String,
     cx: &Context<'_>,
     it: &clean::Item,
     fields: &[clean::Item],
@@ -1876,16 +1942,18 @@ fn item_fields(
                 let field_name =
                     field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
                 let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
-                write!(
+                write_str(
                     w,
-                    "<span id=\"{id}\" class=\"{item_type} section-header\">\
-                         <a href=\"#{id}\" class=\"anchor field\">§</a>\
-                         <code>{field_name}: {ty}</code>\
-                     </span>",
-                    item_type = ItemType::StructField,
-                    ty = ty.print(cx)
+                    format_args!(
+                        "<span id=\"{id}\" class=\"{item_type} section-header\">\
+                            <a href=\"#{id}\" class=\"anchor field\">§</a>\
+                            <code>{field_name}: {ty}</code>\
+                        </span>",
+                        item_type = ItemType::StructField,
+                        ty = ty.print(cx)
+                    ),
                 );
-                write!(w, "{}", document(cx, field, Some(it), HeadingOffset::H3));
+                write_str(w, format_args!("{}", document(cx, field, Some(it), HeadingOffset::H3)));
             }
         }
     }
@@ -1933,8 +2001,8 @@ fn item_foreign_type(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item
         .unwrap();
 }
 
-fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
-    write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
+fn item_keyword(w: &mut String, cx: &Context<'_>, it: &clean::Item) {
+    write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
 }
 
 /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
@@ -2043,34 +2111,33 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
     s
 }
 
-pub(super) fn item_path(ty: ItemType, name: &str) -> String {
-    match ty {
-        ItemType::Module => format!("{}index.html", ensure_trailing_slash(name)),
-        _ => format!("{ty}.{name}.html"),
-    }
+pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display + '_ {
+    fmt::from_fn(move |f| match ty {
+        ItemType::Module => write!(f, "{}index.html", ensure_trailing_slash(name)),
+        _ => write!(f, "{ty}.{name}.html"),
+    })
 }
 
-fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> String {
-    let mut bounds = String::new();
-    if t_bounds.is_empty() {
-        return bounds;
-    }
-    let has_lots_of_bounds = t_bounds.len() > 2;
-    let inter_str = if has_lots_of_bounds { "\n    + " } else { " + " };
-    if !trait_alias {
-        if has_lots_of_bounds {
-            bounds.push_str(":\n    ");
-        } else {
-            bounds.push_str(": ");
-        }
-    }
-    write!(
-        bounds,
-        "{}",
-        fmt::from_fn(|f| t_bounds.iter().map(|p| p.print(cx)).joined(inter_str, f))
-    )
-    .unwrap();
-    bounds
+fn bounds<'a, 'tcx>(
+    bounds: &'a [clean::GenericBound],
+    trait_alias: bool,
+    cx: &'a Context<'tcx>,
+) -> impl Display + 'a + Captures<'tcx> {
+    (!bounds.is_empty())
+        .then_some(fmt::from_fn(move |f| {
+            let has_lots_of_bounds = bounds.len() > 2;
+            let inter_str = if has_lots_of_bounds { "\n    + " } else { " + " };
+            if !trait_alias {
+                if has_lots_of_bounds {
+                    f.write_str(":\n    ")?;
+                } else {
+                    f.write_str(": ")?;
+                }
+            }
+
+            bounds.iter().map(|p| p.print(cx)).joined(inter_str, f)
+        }))
+        .maybe_display()
 }
 
 fn wrap_item<W, F>(w: &mut W, f: F)
@@ -2108,7 +2175,7 @@ fn render_implementor(
     cx: &Context<'_>,
     implementor: &Impl,
     trait_: &clean::Item,
-    w: &mut Buffer,
+    w: &mut String,
     implementor_dups: &FxHashMap<Symbol, (DefId, bool)>,
     aliases: &[String],
 ) {
@@ -2152,10 +2219,9 @@ fn render_union<'a, 'cx: 'a>(
 
         let where_displayed = g
             .map(|g| {
-                let mut buf = Buffer::html();
-                write!(buf, "{}", g.print(cx));
+                let mut buf = g.print(cx).to_string();
                 let where_displayed = print_where_clause_and_check(&mut buf, g, cx);
-                write!(f, "{buf}", buf = buf.into_inner()).unwrap();
+                f.write_str(&buf).unwrap();
                 where_displayed
             })
             .unwrap_or(false);
@@ -2197,7 +2263,7 @@ fn render_union<'a, 'cx: 'a>(
 }
 
 fn render_struct(
-    w: &mut Buffer,
+    w: &mut String,
     it: &clean::Item,
     g: Option<&clean::Generics>,
     ty: Option<CtorKind>,
@@ -2206,15 +2272,17 @@ fn render_struct(
     structhead: bool,
     cx: &Context<'_>,
 ) {
-    write!(
+    write_str(
         w,
-        "{}{}{}",
-        visibility_print_with_space(it, cx),
-        if structhead { "struct " } else { "" },
-        it.name.unwrap()
+        format_args!(
+            "{}{}{}",
+            visibility_print_with_space(it, cx),
+            if structhead { "struct " } else { "" },
+            it.name.unwrap()
+        ),
     );
     if let Some(g) = g {
-        write!(w, "{}", g.print(cx))
+        write_str(w, format_args!("{}", g.print(cx)));
     }
     render_struct_fields(
         w,
@@ -2229,7 +2297,7 @@ fn render_struct(
 }
 
 fn render_struct_fields(
-    mut w: &mut Buffer,
+    mut w: &mut String,
     g: Option<&clean::Generics>,
     ty: Option<CtorKind>,
     fields: &[clean::Item],
@@ -2245,9 +2313,9 @@ fn render_struct_fields(
 
             // If there wasn't a `where` clause, we add a whitespace.
             if !where_displayed {
-                w.write_str(" {");
+                w.push_str(" {");
             } else {
-                w.write_str("{");
+                w.push_str("{");
             }
             let count_fields =
                 fields.iter().filter(|f| matches!(f.kind, clean::StructFieldItem(..))).count();
@@ -2258,66 +2326,82 @@ fn render_struct_fields(
             }
             for field in fields {
                 if let clean::StructFieldItem(ref ty) = field.kind {
-                    write!(
+                    write_str(
                         w,
-                        "\n{tab}    {vis}{name}: {ty},",
-                        vis = visibility_print_with_space(field, cx),
-                        name = field.name.unwrap(),
-                        ty = ty.print(cx),
+                        format_args!(
+                            "\n{tab}    {vis}{name}: {ty},",
+                            vis = visibility_print_with_space(field, cx),
+                            name = field.name.unwrap(),
+                            ty = ty.print(cx)
+                        ),
                     );
                 }
             }
 
             if has_visible_fields {
                 if has_stripped_entries {
-                    write!(w, "\n{tab}    <span class=\"comment\">/* private fields */</span>");
+                    write_str(
+                        w,
+                        format_args!(
+                            "\n{tab}    <span class=\"comment\">/* private fields */</span>"
+                        ),
+                    );
                 }
-                write!(w, "\n{tab}");
+                write_str(w, format_args!("\n{tab}"));
             } else if has_stripped_entries {
-                write!(w, " <span class=\"comment\">/* private fields */</span> ");
+                write_str(w, format_args!(" <span class=\"comment\">/* private fields */</span> "));
             }
             if toggle {
                 toggle_close(&mut w);
             }
-            w.write_str("}");
+            w.push_str("}");
         }
         Some(CtorKind::Fn) => {
-            w.write_str("(");
+            w.push_str("(");
             if !fields.is_empty()
                 && fields.iter().all(|field| {
                     matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
                 })
             {
-                write!(w, "<span class=\"comment\">/* private fields */</span>");
+                write_str(w, format_args!("<span class=\"comment\">/* private fields */</span>"));
             } else {
                 for (i, field) in fields.iter().enumerate() {
                     if i > 0 {
-                        w.write_str(", ");
+                        w.push_str(", ");
                     }
                     match field.kind {
-                        clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
+                        clean::StrippedItem(box clean::StructFieldItem(..)) => {
+                            write_str(w, format_args!("_"));
+                        }
                         clean::StructFieldItem(ref ty) => {
-                            write!(w, "{}{}", visibility_print_with_space(field, cx), ty.print(cx),)
+                            write_str(
+                                w,
+                                format_args!(
+                                    "{}{}",
+                                    visibility_print_with_space(field, cx),
+                                    ty.print(cx)
+                                ),
+                            );
                         }
                         _ => unreachable!(),
                     }
                 }
             }
-            w.write_str(")");
+            w.push_str(")");
             if let Some(g) = g {
-                write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
+                write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline)));
             }
             // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
             if structhead {
-                w.write_str(";");
+                w.push_str(";");
             }
         }
         Some(CtorKind::Const) => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
+                write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline)));
             }
-            w.write_str(";");
+            w.push_str(";");
         }
     }
 }
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index e4a9a2b512e..95f617c9839 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -821,7 +821,7 @@ pub(crate) fn get_function_type_for_search(
                     .map(|name| clean::PathSegment {
                         name: *name,
                         args: clean::GenericArgs::AngleBracketed {
-                            args: Vec::new().into_boxed_slice(),
+                            args: ThinVec::new(),
                             constraints: ThinVec::new(),
                         },
                     })
@@ -1265,13 +1265,14 @@ fn simplify_fn_type<'a, 'tcx>(
                                 *stored_bounds = type_bounds;
                             }
                         }
-                        ty_constraints.push((RenderTypeId::AssociatedType(name), vec![
-                            RenderType {
+                        ty_constraints.push((
+                            RenderTypeId::AssociatedType(name),
+                            vec![RenderType {
                                 id: Some(RenderTypeId::Index(idx)),
                                 generics: None,
                                 bindings: None,
-                            },
-                        ]))
+                            }],
+                        ))
                     }
                 }
             }
diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs
index 23ac568fdf8..64dbaf9083e 100644
--- a/src/librustdoc/html/render/sidebar.rs
+++ b/src/librustdoc/html/render/sidebar.rs
@@ -1,4 +1,5 @@
 use std::borrow::Cow;
+use std::cmp::Ordering;
 
 use rinja::Template;
 use rustc_data_structures::fx::FxHashSet;
@@ -11,8 +12,8 @@ use super::{Context, ItemSection, item_ty_to_section};
 use crate::clean;
 use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
-use crate::html::format::Buffer;
 use crate::html::markdown::{IdMap, MarkdownWithToc};
+use crate::html::render::print_item::compare_names;
 
 #[derive(Clone, Copy)]
 pub(crate) enum ModuleLike {
@@ -78,7 +79,7 @@ impl<'a> LinkBlock<'a> {
 }
 
 /// A link to an item. Content should not be escaped.
-#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone)]
+#[derive(Ord, PartialEq, Eq, Hash, Clone)]
 pub(crate) struct Link<'a> {
     /// The content for the anchor tag and title attr
     name: Cow<'a, str>,
@@ -90,6 +91,20 @@ pub(crate) struct Link<'a> {
     children: Vec<Link<'a>>,
 }
 
+impl PartialOrd for Link<'_> {
+    fn partial_cmp(&self, other: &Link<'_>) -> Option<Ordering> {
+        match compare_names(&self.name, &other.name) {
+            Ordering::Equal => (),
+            result => return Some(result),
+        }
+        (&self.name_html, &self.href, &self.children).partial_cmp(&(
+            &other.name_html,
+            &other.href,
+            &other.children,
+        ))
+    }
+}
+
 impl<'a> Link<'a> {
     pub fn new(href: impl Into<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> Self {
         Self { href: href.into(), name: name.into(), children: vec![], name_html: None }
@@ -114,7 +129,7 @@ pub(crate) mod filters {
     }
 }
 
-pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
+pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut String) {
     let mut ids = IdMap::new();
     let mut blocks: Vec<LinkBlock<'_>> = docblock_toc(cx, it, &mut ids).into_iter().collect();
     let deref_id_map = cx.deref_id_map.borrow();
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index a15ac155123..ce9c42c01cc 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -51,7 +51,7 @@ pub(crate) fn collect_spans_and_sources(
         let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
 
         if generate_link_to_definition {
-            tcx.hir().walk_toplevel_module(&mut visitor);
+            tcx.hir_walk_toplevel_module(&mut visitor);
         }
         let sources = sources::collect_local_sources(tcx, src_root, krate);
         (sources, visitor.matches)
@@ -173,18 +173,18 @@ impl SpanMapVisitor<'_> {
     }
 
     fn infer_id(&mut self, hir_id: HirId, expr_hir_id: Option<HirId>, span: Span) {
-        let hir = self.tcx.hir();
-        let body_id = hir.enclosing_body_owner(hir_id);
+        let tcx = self.tcx;
+        let body_id = tcx.hir_enclosing_body_owner(hir_id);
         // FIXME: this is showing error messages for parts of the code that are not
         // compiled (because of cfg)!
         //
         // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
-        let typeck_results = self.tcx.typeck_body(hir.body_owned_by(body_id).id());
+        let typeck_results = tcx.typeck_body(tcx.hir_body_owned_by(body_id).id());
         // Interestingly enough, for method calls, we need the whole expression whereas for static
         // method/function calls, we need the call expression specifically.
         if let Some(def_id) = typeck_results.type_dependent_def_id(expr_hir_id.unwrap_or(hir_id)) {
             let link = if def_id.as_local().is_some() {
-                LinkFromSrc::Local(rustc_span(def_id, self.tcx))
+                LinkFromSrc::Local(rustc_span(def_id, tcx))
             } else {
                 LinkFromSrc::External(def_id)
             };
@@ -221,8 +221,8 @@ impl SpanMapVisitor<'_> {
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_path(&mut self, path: &rustc_hir::Path<'tcx>, _id: HirId) {
@@ -288,7 +288,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             | ItemKind::Use(_, _)
             | ItemKind::ExternCrate(_)
             | ItemKind::ForeignMod { .. }
-            | ItemKind::GlobalAsm(_)
+            | ItemKind::GlobalAsm { .. }
             // We already have "visit_mod" above so no need to check it here.
             | ItemKind::Mod(_) => {}
         }
diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs
index 4a9724a6f84..657cd3c82aa 100644
--- a/src/librustdoc/html/render/tests.rs
+++ b/src/librustdoc/html/render/tests.rs
@@ -1,7 +1,7 @@
 use std::cmp::Ordering;
 
+use super::AllTypes;
 use super::print_item::compare_names;
-use super::{AllTypes, Buffer};
 
 #[test]
 fn test_compare_names() {
@@ -47,8 +47,8 @@ fn test_all_types_prints_header_once() {
     // Regression test for #82477
     let all_types = AllTypes::new();
 
-    let mut buffer = Buffer::new();
+    let mut buffer = String::new();
     all_types.print(&mut buffer);
 
-    assert_eq!(1, buffer.into_inner().matches("List of all items").count());
+    assert_eq!(1, buffer.matches("List of all items").count());
 }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index fb6f3bc2c76..a4dec013fc0 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -44,7 +44,6 @@ use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::Impl;
 use crate::formats::item_type::ItemType;
-use crate::html::format::Buffer;
 use crate::html::layout;
 use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
 use crate::html::render::search_index::{SerializedSearchIndex, build_index};
@@ -207,14 +206,8 @@ fn write_static_files(
     if opt.emit.is_empty() || opt.emit.contains(&EmitType::Toolchain) {
         static_files::for_each(|f: &static_files::StaticFile| {
             let filename = static_dir.join(f.output_filename());
-            let contents: &[u8];
-            let contents_vec: Vec<u8>;
-            if opt.disable_minification {
-                contents = f.bytes;
-            } else {
-                contents_vec = f.minified();
-                contents = &contents_vec;
-            };
+            let contents: &[u8] =
+                if opt.disable_minification { f.src_bytes } else { f.minified_bytes };
             fs::write(&filename, contents).map_err(|e| PathError::new(e, &filename))
         })?;
     }
@@ -628,7 +621,6 @@ impl TypeAliasPart {
                     // to make that functionality work here, it needs to be called with
                     // each type alias, and if it gives a different result, split the impl
                     for &(type_alias_fqp, type_alias_item) in type_aliases {
-                        let mut buf = Buffer::html();
                         cx.id_map.borrow_mut().clear();
                         cx.deref_id_map.borrow_mut().clear();
                         let target_did = impl_
@@ -644,23 +636,26 @@ impl TypeAliasPart {
                         } else {
                             AssocItemLink::Anchor(None)
                         };
-                        super::render_impl(
-                            &mut buf,
-                            cx,
-                            impl_,
-                            type_alias_item,
-                            assoc_link,
-                            RenderMode::Normal,
-                            None,
-                            &[],
-                            ImplRenderingParameters {
-                                show_def_docs: true,
-                                show_default_items: true,
-                                show_non_assoc_items: true,
-                                toggle_open_by_default: true,
-                            },
-                        );
-                        let text = buf.into_inner();
+                        let text = {
+                            let mut buf = String::new();
+                            super::render_impl(
+                                &mut buf,
+                                cx,
+                                impl_,
+                                type_alias_item,
+                                assoc_link,
+                                RenderMode::Normal,
+                                None,
+                                &[],
+                                ImplRenderingParameters {
+                                    show_def_docs: true,
+                                    show_default_items: true,
+                                    show_non_assoc_items: true,
+                                    toggle_open_by_default: true,
+                                },
+                            );
+                            buf
+                        };
                         let type_alias_fqp = (*type_alias_fqp).iter().join("::");
                         if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) {
                             ret.last_mut()
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 1ac0c10c612..78c86a27632 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -1,6 +1,5 @@
 use std::cell::RefCell;
 use std::ffi::OsStr;
-use std::ops::RangeInclusive;
 use std::path::{Component, Path, PathBuf};
 use std::{fmt, fs};
 
@@ -12,12 +11,13 @@ use rustc_session::Session;
 use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, sym};
 use tracing::info;
 
+use super::highlight;
+use super::layout::{self, BufDisplay};
+use super::render::Context;
 use crate::clean;
 use crate::clean::utils::has_doc_flag;
 use crate::docfs::PathError;
 use crate::error::Error;
-use crate::html::render::Context;
-use crate::html::{highlight, layout};
 use crate::visit::DocVisitor;
 
 pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
@@ -238,11 +238,12 @@ impl SourceCollector<'_, '_> {
             resource_suffix: &shared.resource_suffix,
             rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
         };
+        let source_context = SourceContext::Standalone { file_path };
         let v = layout::render(
             &shared.layout,
             &page,
             "",
-            |buf: &mut _| {
+            BufDisplay(|buf: &mut String| {
                 print_src(
                     buf,
                     contents,
@@ -250,9 +251,9 @@ impl SourceCollector<'_, '_> {
                     self.cx,
                     &root_path,
                     &highlight::DecorationInfo::default(),
-                    SourceContext::Standalone { file_path },
-                )
-            },
+                    &source_context,
+                );
+            }),
             &shared.style_files,
         );
         shared.fs.write(cur, v)?;
@@ -302,17 +303,17 @@ pub(crate) struct ScrapedInfo<'a> {
 #[derive(Template)]
 #[template(path = "scraped_source.html")]
 struct ScrapedSource<'a, Code: std::fmt::Display> {
-    info: ScrapedInfo<'a>,
-    lines: RangeInclusive<usize>,
+    info: &'a ScrapedInfo<'a>,
     code_html: Code,
+    max_nb_digits: u32,
 }
 
 #[derive(Template)]
 #[template(path = "source.html")]
 struct Source<Code: std::fmt::Display> {
-    lines: RangeInclusive<usize>,
     code_html: Code,
     file_path: Option<(String, String)>,
+    max_nb_digits: u32,
 }
 
 pub(crate) enum SourceContext<'a> {
@@ -329,8 +330,17 @@ pub(crate) fn print_src(
     context: &Context<'_>,
     root_path: &str,
     decoration_info: &highlight::DecorationInfo,
-    source_context: SourceContext<'_>,
+    source_context: &SourceContext<'_>,
 ) {
+    let mut lines = s.lines().count();
+    let line_info = if let SourceContext::Embedded(ref info) = source_context {
+        highlight::LineInfo::new_scraped(lines as u32, info.offset as u32)
+    } else {
+        highlight::LineInfo::new(lines as u32)
+    };
+    if line_info.is_scraped_example {
+        lines += line_info.start_line as usize;
+    }
     let code = fmt::from_fn(move |fmt| {
         let current_href = context
             .href_from_span(clean::Span::new(file_span), false)
@@ -340,13 +350,13 @@ pub(crate) fn print_src(
             s,
             Some(highlight::HrefContext { context, file_span, root_path, current_href }),
             Some(decoration_info),
+            Some(line_info),
         );
         Ok(())
     });
-    let lines = s.lines().count();
+    let max_nb_digits = if lines > 0 { lines.ilog(10) + 1 } else { 1 };
     match source_context {
         SourceContext::Standalone { file_path } => Source {
-            lines: (1..=lines),
             code_html: code,
             file_path: if let Some(file_name) = file_path.file_name()
                 && let Some(file_path) = file_path.parent()
@@ -355,12 +365,14 @@ pub(crate) fn print_src(
             } else {
                 None
             },
+            max_nb_digits,
         }
         .render_into(&mut writer)
         .unwrap(),
         SourceContext::Embedded(info) => {
-            let lines = (1 + info.offset)..=(lines + info.offset);
-            ScrapedSource { info, lines, code_html: code }.render_into(&mut writer).unwrap();
+            ScrapedSource { info, code_html: code, max_nb_digits }
+                .render_into(&mut writer)
+                .unwrap();
         }
     };
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index d0612e997fd..4f5f8f92264 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -40,6 +40,20 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 	--docblock-indent: 24px;
 	--font-family: "Source Serif 4", NanumBarunGothic, serif;
 	--font-family-code: "Source Code Pro", monospace;
+	--line-number-padding: 4px;
+	/* scraped examples icons (34x33px) */
+	--prev-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
+	enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
+	d="M8,3l-4,5l4,5m-4,-5h10" stroke="black" stroke-width="2"/></svg>');
+	--next-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
+	enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
+	d="M8,3l4,5l-4,5m4,-5h-10" stroke="black" stroke-width="2"/></svg>');
+	--expand-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
+	enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
+	d="M3,10l4,4l4,-4m-4,4M3,7l4,-4l4,4" stroke="black" stroke-width="2"/></svg>');
+	--collapse-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
+	enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
+	d="M3,8l4,4l4,-4m-4,4M3,4l4,4l4,-4" stroke="black" stroke-width="2"/></svg>');
 }
 
 :root.sans-serif {
@@ -450,9 +464,7 @@ pre.item-decl {
 
 .src .content pre {
 	padding: 20px;
-}
-.rustdoc.src .example-wrap .src-line-numbers  {
-	padding: 20px 0 20px 4px;
+	padding-left: 16px;
 }
 
 img {
@@ -901,29 +913,58 @@ both the code example and the line numbers, so we need to remove the radius in t
 	min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */
 	flex-grow: 0;
 	text-align: right;
+	-moz-user-select: none;
 	-webkit-user-select: none;
+	-ms-user-select: none;
 	user-select: none;
 	padding: 14px 8px;
 	padding-right: 2px;
 	color: var(--src-line-numbers-span-color);
 }
 
-.rustdoc .scraped-example .example-wrap .src-line-numbers {
-	padding: 0;
+.example-wrap.digits-1 [data-nosnippet] {
+	width: calc(1ch + var(--line-number-padding) * 2);
+}
+.example-wrap.digits-2 [data-nosnippet] {
+	width: calc(2ch + var(--line-number-padding) * 2);
+}
+.example-wrap.digits-3 [data-nosnippet] {
+	width: calc(3ch + var(--line-number-padding) * 2);
+}
+.example-wrap.digits-4 [data-nosnippet] {
+	width: calc(4ch + var(--line-number-padding) * 2);
+}
+.example-wrap.digits-5 [data-nosnippet] {
+	width: calc(5ch + var(--line-number-padding) * 2);
 }
-.rustdoc .src-line-numbers pre {
-	padding: 14px 0;
+.example-wrap.digits-6 [data-nosnippet] {
+	width: calc(6ch + var(--line-number-padding) * 2);
 }
-.src-line-numbers a, .src-line-numbers span {
+.example-wrap.digits-7 [data-nosnippet] {
+	width: calc(7ch + var(--line-number-padding) * 2);
+}
+.example-wrap.digits-8 [data-nosnippet] {
+	width: calc(8ch + var(--line-number-padding) * 2);
+}
+.example-wrap.digits-9 [data-nosnippet] {
+	width: calc(9ch + var(--line-number-padding) * 2);
+}
+
+.example-wrap [data-nosnippet] {
 	color: var(--src-line-numbers-span-color);
-	padding: 0 8px;
+	text-align: right;
+	display: inline-block;
+	margin-right: 20px;
+	-moz-user-select: none;
+	-webkit-user-select: none;
+	-ms-user-select: none;
+	user-select: none;
+	padding: 0 4px;
 }
-.src-line-numbers :target {
-	background-color: transparent;
+.example-wrap [data-nosnippet]:target {
 	border-right: none;
-	padding: 0 8px;
 }
-.src-line-numbers .line-highlighted {
+.example-wrap .line-highlighted[data-nosnippet] {
 	background-color: var(--src-line-number-highlighted-background-color);
 }
 
@@ -1110,7 +1151,7 @@ because of the `[-]` element which would overlap with it. */
 }
 
 .main-heading a:hover,
-.example-wrap .rust a:hover,
+.example-wrap .rust a:hover:not([data-nosnippet]),
 .all-items a:hover,
 .docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),
 .item-table dd a:not(.scrape-help):not(.tooltip):hover,
@@ -1568,7 +1609,7 @@ pre.rust .doccomment {
 	color: var(--code-highlight-doc-comment-color);
 }
 
-.rustdoc.src .example-wrap pre.rust a {
+.rustdoc.src .example-wrap pre.rust a:not([data-nosnippet]) {
 	background: var(--codeblock-link-background);
 }
 
@@ -1701,7 +1742,10 @@ instead, we check that it's not a "finger" cursor.
 	padding: 2px 0 0 4px;
 }
 .example-wrap .button-holder .copy-button::before,
-.example-wrap .test-arrow::before {
+.example-wrap .test-arrow::before,
+.example-wrap .button-holder .prev::before,
+.example-wrap .button-holder .next::before,
+.example-wrap .button-holder .expand::before {
 	filter: var(--copy-path-img-filter);
 }
 .example-wrap .button-holder .copy-button::before {
@@ -1716,6 +1760,24 @@ instead, we check that it's not a "finger" cursor.
 	padding-right: 5px;
 }
 
+.example-wrap .button-holder .prev,
+.example-wrap .button-holder .next,
+.example-wrap .button-holder .expand {
+	line-height: 0px;
+}
+.example-wrap .button-holder .prev::before {
+	content: var(--prev-arrow-image);
+}
+.example-wrap .button-holder .next::before {
+	content: var(--next-arrow-image);
+}
+.example-wrap .button-holder .expand::before {
+	content: var(--expand-arrow-image);
+}
+.example-wrap .button-holder .expand.collapse::before {
+	content: var(--collapse-arrow-image);
+}
+
 .code-attribute {
 	font-weight: 300;
 	color: var(--code-attribute-color);
@@ -1759,8 +1821,7 @@ instead, we check that it's not a "finger" cursor.
 	}
 }
 
-:target {
-	padding-right: 3px;
+:target:not([data-nosnippet]) {
 	background-color: var(--target-background-color);
 	border-right: 3px solid var(--target-border-color);
 }
@@ -1985,6 +2046,13 @@ button#toggle-all-docs:before {
 	filter: var(--settings-menu-filter);
 }
 
+button#toggle-all-docs.will-expand:before {
+	/* Custom arrow icon */
+	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
+	enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
+	<path d="M2,5l4,-4l4,4M2,7l4,4l4,-4" stroke="black" fill="none" stroke-width="2px"/></svg>');
+}
+
 #help-button > a:before {
 	/* Question mark with circle */
 	content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
@@ -3153,7 +3221,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	color: #ff7733;
 }
 
-:root[data-theme="ayu"] .src-line-numbers .line-highlighted {
+:root[data-theme="ayu"] a[data-nosnippet].line-highlighted {
 	color: #708090;
 	padding-right: 7px;
 	border-right: 1px solid #ffb44c;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index a348c6c5678..e46cc1897e9 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -2039,7 +2039,10 @@ function preLoadCss(cssUrl) {
         // Most page titles are '<Item> in <path::to::module> - Rust', except
         // modules (which don't have the first part) and keywords/primitives
         // (which don't have a module path)
-        const [item, module] = document.title.split(" in ");
+        const titleElement = document.querySelector("title");
+        const title = titleElement && titleElement.textContent ?
+                      titleElement.textContent.replace(" - Rust", "") : "";
+        const [item, module] = title.split(" in ");
         const path = [item];
         if (module !== undefined) {
             path.unshift(module);
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
index d08f15a5bfa..d641405c875 100644
--- a/src/librustdoc/html/static/js/scrape-examples.js
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -16,7 +16,7 @@
 
     // Scroll code block to the given code location
     function scrollToLoc(elt, loc, isHidden) {
-        const lines = elt.querySelector(".src-line-numbers > pre");
+        const lines = elt.querySelectorAll("[data-nosnippet]");
         let scrollOffset;
 
         // If the block is greater than the size of the viewer,
@@ -25,24 +25,24 @@
         const maxLines = isHidden ? HIDDEN_MAX_LINES : DEFAULT_MAX_LINES;
         if (loc[1] - loc[0] > maxLines) {
             const line = Math.max(0, loc[0] - 1);
-            scrollOffset = lines.children[line].offsetTop;
+            scrollOffset = lines[line].offsetTop;
         } else {
             const halfHeight = elt.offsetHeight / 2;
-            const offsetTop = lines.children[loc[0]].offsetTop;
-            const lastLine = lines.children[loc[1]];
+            const offsetTop = lines[loc[0]].offsetTop;
+            const lastLine = lines[loc[1]];
             const offsetBot = lastLine.offsetTop + lastLine.offsetHeight;
             const offsetMid = (offsetTop + offsetBot) / 2;
             scrollOffset = offsetMid - halfHeight;
         }
 
-        lines.parentElement.scrollTo(0, scrollOffset);
+        lines[0].parentElement.scrollTo(0, scrollOffset);
         elt.querySelector(".rust").scrollTo(0, scrollOffset);
     }
 
     function createScrapeButton(parent, className, content) {
         const button = document.createElement("button");
         button.className = className;
-        button.innerText = content;
+        button.title = content;
         parent.insertBefore(button, parent.firstChild);
         return button;
     }
@@ -54,14 +54,14 @@
         let expandButton = null;
 
         if (!example.classList.contains("expanded")) {
-            expandButton = createScrapeButton(buttonHolder, "expand", "↕");
+            expandButton = createScrapeButton(buttonHolder, "expand", "Show all");
         }
         const isHidden = example.parentElement.classList.contains("more-scraped-examples");
 
         const locs = example.locs;
         if (locs.length > 1) {
-            const next = createScrapeButton(buttonHolder, "next", "≻");
-            const prev = createScrapeButton(buttonHolder, "prev", "≺");
+            const next = createScrapeButton(buttonHolder, "next", "Next usage");
+            const prev = createScrapeButton(buttonHolder, "prev", "Previous usage");
 
             // Toggle through list of examples in a given file
             const onChangeLoc = changeIndex => {
@@ -94,9 +94,13 @@
             expandButton.addEventListener("click", () => {
                 if (hasClass(example, "expanded")) {
                     removeClass(example, "expanded");
+                    removeClass(expandButton, "collapse");
+                    expandButton.title = "Show all";
                     scrollToLoc(example, locs[0][0], isHidden);
                 } else {
                     addClass(example, "expanded");
+                    addClass(expandButton, "collapse");
+                    expandButton.title = "Show single example";
                 }
             });
         }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 121a43e3d92..ccbd6811b07 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -5318,8 +5318,9 @@ function registerSearchEvents() {
 
     // @ts-expect-error
     searchState.input.addEventListener("blur", () => {
-        // @ts-expect-error
-        searchState.input.placeholder = searchState.input.origPlaceholder;
+        if (window.searchState.input) {
+            window.searchState.input.placeholder = window.searchState.origPlaceholder;
+        }
     });
 
     // Push and pop states are used to add search results to the browser
diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js
index 8f712f4c20c..fc27241334b 100644
--- a/src/librustdoc/html/static/js/src-script.js
+++ b/src/librustdoc/html/static/js/src-script.js
@@ -138,10 +138,8 @@ function highlightSrcLines() {
     if (x) {
         x.scrollIntoView();
     }
-    onEachLazy(document.getElementsByClassName("src-line-numbers"), e => {
-        onEachLazy(e.getElementsByTagName("a"), i_e => {
-            removeClass(i_e, "line-highlighted");
-        });
+    onEachLazy(document.querySelectorAll("a[data-nosnippet]"), e => {
+        removeClass(e, "line-highlighted");
     });
     for (let i = from; i <= to; ++i) {
         elem = document.getElementById(i);
@@ -200,7 +198,7 @@ const handleSrcHighlight = (function() {
 
 window.addEventListener("hashchange", highlightSrcLines);
 
-onEachLazy(document.getElementsByClassName("src-line-numbers"), el => {
+onEachLazy(document.querySelectorAll("a[data-nosnippet]"), el => {
     el.addEventListener("click", handleSrcHighlight);
 });
 
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index 0bcaf11da0c..45589a37069 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -8,26 +8,18 @@ use std::{fmt, str};
 
 pub(crate) struct StaticFile {
     pub(crate) filename: PathBuf,
-    pub(crate) bytes: &'static [u8],
+    pub(crate) src_bytes: &'static [u8],
+    pub(crate) minified_bytes: &'static [u8],
 }
 
 impl StaticFile {
-    fn new(filename: &str, bytes: &'static [u8], sha256: &'static str) -> StaticFile {
-        Self { filename: static_filename(filename, sha256), bytes }
-    }
-
-    pub(crate) fn minified(&self) -> Vec<u8> {
-        let extension = match self.filename.extension() {
-            Some(e) => e,
-            None => return self.bytes.to_owned(),
-        };
-        if extension == "css" {
-            minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
-        } else if extension == "js" {
-            minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
-        } else {
-            self.bytes.to_owned()
-        }
+    fn new(
+        filename: &str,
+        src_bytes: &'static [u8],
+        minified_bytes: &'static [u8],
+        sha256: &'static str,
+    ) -> StaticFile {
+        Self { filename: static_filename(filename, sha256), src_bytes, minified_bytes }
     }
 
     pub(crate) fn output_filename(&self) -> &Path {
@@ -68,7 +60,7 @@ macro_rules! static_files {
 
         // sha256 files are generated in build.rs
         pub(crate) static STATIC_FILES: std::sync::LazyLock<StaticFiles> = std::sync::LazyLock::new(|| StaticFiles {
-            $($field: StaticFile::new($file_path, include_bytes!($file_path), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+
+            $($field: StaticFile::new($file_path, include_bytes!($file_path), include_bytes!(concat!(env!("OUT_DIR"), "/", $file_path, ".min")), include_str!(concat!(env!("OUT_DIR"), "/", $file_path, ".sha256"))),)+
         });
 
         pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> {
diff --git a/src/librustdoc/html/templates/scraped_source.html b/src/librustdoc/html/templates/scraped_source.html
index bd54bbf58d5..3e69f1c8cad 100644
--- a/src/librustdoc/html/templates/scraped_source.html
+++ b/src/librustdoc/html/templates/scraped_source.html
@@ -2,17 +2,7 @@
     <div class="scraped-example-title">
        {{info.name +}} (<a href="{{info.url}}">{{info.title}}</a>) {# #}
     </div> {# #}
-    <div class="example-wrap">
-        {# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
-           Do not show "1 2 3 4 5 ..." in web search results. #}
-        <div class="src-line-numbers" data-nosnippet> {# #}
-            <pre>
-                {% for line in lines.clone() %}
-                    {# ~#}
-                    <span>{{line|safe}}</span>
-                {% endfor %}
-            </pre> {# #}
-        </div> {# #}
+    <div class="example-wrap digits-{{max_nb_digits}}"> {# #}
         <pre class="rust"> {# #}
             <code>
                 {{code_html|safe}}
diff --git a/src/librustdoc/html/templates/source.html b/src/librustdoc/html/templates/source.html
index ea530087e6f..454d4c27f1a 100644
--- a/src/librustdoc/html/templates/source.html
+++ b/src/librustdoc/html/templates/source.html
@@ -9,15 +9,7 @@
 </div>
 {% else %}
 {% endmatch %}
-<div class="example-wrap">
-    {# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
-       Do not show "1 2 3 4 5 ..." in web search results. #}
-    <div data-nosnippet><pre class="src-line-numbers">
-        {% for line in lines.clone() %}
-            {# ~#}
-            <a href="#{{line|safe}}" id="{{line|safe}}">{{line|safe}}</a>
-        {% endfor %}
-    </pre></div> {# #}
+<div class="example-wrap digits-{{max_nb_digits}}"> {# #}
     <pre class="rust"> {# #}
         <code>
             {{code_html|safe}}