Skip to content

Commit d6cfa0b

Browse files
committed
Lazy-ify some markdown rendering
1 parent 22be76b commit d6cfa0b

File tree

6 files changed

+101
-84
lines changed

6 files changed

+101
-84
lines changed

src/librustdoc/externalfiles.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,9 @@ impl ExternalHtml {
3535
) -> Option<ExternalHtml> {
3636
let codes = ErrorCodes::from(nightly_build);
3737
let ih = load_external_files(in_header, dcx)?;
38-
let bc = load_external_files(before_content, dcx)?;
39-
let m_bc = load_external_files(md_before_content, dcx)?;
40-
let bc = format!(
41-
"{bc}{}",
38+
let bc = {
39+
let mut bc = load_external_files(before_content, dcx)?;
40+
let m_bc = load_external_files(md_before_content, dcx)?;
4241
Markdown {
4342
content: &m_bc,
4443
links: &[],
@@ -48,12 +47,13 @@ impl ExternalHtml {
4847
playground,
4948
heading_offset: HeadingOffset::H2,
5049
}
51-
.into_string()
52-
);
53-
let ac = load_external_files(after_content, dcx)?;
54-
let m_ac = load_external_files(md_after_content, dcx)?;
55-
let ac = format!(
56-
"{ac}{}",
50+
.write_into(&mut bc)
51+
.unwrap();
52+
bc
53+
};
54+
let ac = {
55+
let mut ac = load_external_files(after_content, dcx)?;
56+
let m_ac = load_external_files(md_after_content, dcx)?;
5757
Markdown {
5858
content: &m_ac,
5959
links: &[],
@@ -63,8 +63,10 @@ impl ExternalHtml {
6363
playground,
6464
heading_offset: HeadingOffset::H2,
6565
}
66-
.into_string()
67-
);
66+
.write_into(&mut ac)
67+
.unwrap();
68+
ac
69+
};
6870
Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
6971
}
7072
}

src/librustdoc/html/markdown.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@
2121
//! playground: &None,
2222
//! heading_offset: HeadingOffset::H2,
2323
//! };
24-
//! let html = md.into_string();
24+
//! let mut html = String::new();
25+
//! md.write_into(&mut html).unwrap();
2526
//! // ... something using html
2627
//! ```
2728
2829
use std::borrow::Cow;
2930
use std::collections::VecDeque;
30-
use std::fmt::Write;
31+
use std::fmt::{self, Write};
3132
use std::iter::Peekable;
3233
use std::ops::{ControlFlow, Range};
3334
use std::path::PathBuf;
@@ -1327,17 +1328,32 @@ impl LangString {
13271328
}
13281329
}
13291330

1331+
trait WriteSpec {
1332+
fn reserve_spec(&mut self, additional: usize);
1333+
}
1334+
1335+
impl<W: fmt::Write> WriteSpec for W {
1336+
#[inline]
1337+
default fn reserve_spec(&mut self, _additional: usize) {}
1338+
}
1339+
1340+
impl<'a> WriteSpec for &'a mut String {
1341+
#[inline]
1342+
fn reserve_spec(&mut self, additional: usize) {
1343+
self.reserve(additional);
1344+
}
1345+
}
1346+
13301347
impl<'a> Markdown<'a> {
1331-
pub fn into_string(self) -> String {
1348+
pub fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
13321349
// This is actually common enough to special-case
13331350
if self.content.is_empty() {
1334-
return String::new();
1351+
return Ok(());
13351352
}
13361353

1337-
let mut s = String::with_capacity(self.content.len() * 3 / 2);
1338-
html::push_html(&mut s, self.into_iter());
1354+
f.reserve_spec(self.content.len() * 3 / 2);
13391355

1340-
s
1356+
html::write_html_fmt(f, self.into_iter())
13411357
}
13421358

13431359
fn into_iter(self) -> CodeBlocks<'a, 'a, impl Iterator<Item = Event<'a>>> {
@@ -1453,19 +1469,20 @@ impl MarkdownWithToc<'_> {
14531469

14541470
(toc.into_toc(), s)
14551471
}
1456-
pub(crate) fn into_string(self) -> String {
1472+
1473+
pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
14571474
let (toc, s) = self.into_parts();
1458-
format!("<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
1475+
write!(f, "<nav id=\"rustdoc\">{toc}</nav>{s}", toc = toc.print())
14591476
}
14601477
}
14611478

14621479
impl MarkdownItemInfo<'_> {
1463-
pub(crate) fn into_string(self) -> String {
1480+
pub(crate) fn write_into(self, mut f: impl fmt::Write) -> fmt::Result {
14641481
let MarkdownItemInfo(md, ids) = self;
14651482

14661483
// This is actually common enough to special-case
14671484
if md.is_empty() {
1468-
return String::new();
1485+
return Ok(());
14691486
}
14701487
let p = Parser::new_ext(md, main_body_opts()).into_offset_iter();
14711488

@@ -1475,7 +1492,7 @@ impl MarkdownItemInfo<'_> {
14751492
_ => event,
14761493
});
14771494

1478-
let mut s = String::with_capacity(md.len() * 3 / 2);
1495+
f.reserve_spec(md.len() * 3 / 2);
14791496

14801497
ids.handle_footnotes(|ids, existing_footnotes| {
14811498
let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
@@ -1484,10 +1501,8 @@ impl MarkdownItemInfo<'_> {
14841501
let p = p.filter(|event| {
14851502
!matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
14861503
});
1487-
html::push_html(&mut s, p);
1488-
});
1489-
1490-
s
1504+
html::write_html_fmt(&mut f, p)
1505+
})
14911506
}
14921507
}
14931508

src/librustdoc/html/markdown/tests.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,8 @@ fn test_lang_string_tokenizer() {
297297
fn test_header() {
298298
fn t(input: &str, expect: &str) {
299299
let mut map = IdMap::new();
300-
let output = Markdown {
300+
let mut output = String::new();
301+
Markdown {
301302
content: input,
302303
links: &[],
303304
ids: &mut map,
@@ -306,7 +307,8 @@ fn test_header() {
306307
playground: &None,
307308
heading_offset: HeadingOffset::H2,
308309
}
309-
.into_string();
310+
.write_into(&mut output)
311+
.unwrap();
310312
assert_eq!(output, expect, "original: {}", input);
311313
}
312314

@@ -348,7 +350,8 @@ fn test_header() {
348350
fn test_header_ids_multiple_blocks() {
349351
let mut map = IdMap::new();
350352
fn t(map: &mut IdMap, input: &str, expect: &str) {
351-
let output = Markdown {
353+
let mut output = String::new();
354+
Markdown {
352355
content: input,
353356
links: &[],
354357
ids: map,
@@ -357,7 +360,8 @@ fn test_header_ids_multiple_blocks() {
357360
playground: &None,
358361
heading_offset: HeadingOffset::H2,
359362
}
360-
.into_string();
363+
.write_into(&mut output)
364+
.unwrap();
361365
assert_eq!(output, expect, "original: {}", input);
362366
}
363367

@@ -496,7 +500,8 @@ fn test_find_testable_code_line() {
496500
fn test_ascii_with_prepending_hashtag() {
497501
fn t(input: &str, expect: &str) {
498502
let mut map = IdMap::new();
499-
let output = Markdown {
503+
let mut output = String::new();
504+
Markdown {
500505
content: input,
501506
links: &[],
502507
ids: &mut map,
@@ -505,7 +510,8 @@ fn test_ascii_with_prepending_hashtag() {
505510
playground: &None,
506511
heading_offset: HeadingOffset::H2,
507512
}
508-
.into_string();
513+
.write_into(&mut output)
514+
.unwrap();
509515
assert_eq!(output, expect, "original: {}", input);
510516
}
511517

src/librustdoc/html/render/mod.rs

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -508,22 +508,21 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
508508
the Rustdoc book]({DOC_RUST_LANG_ORG_VERSION}/rustdoc/scraped-examples.html)."
509509
));
510510

511-
let mut ids = IdMap::default();
512511
format!(
513512
"<div class=\"main-heading\">\
514513
<h1>About scraped examples</h1>\
515514
</div>\
516515
<div>{}</div>",
517-
Markdown {
516+
fmt::from_fn(|f| Markdown {
518517
content: &content,
519518
links: &[],
520-
ids: &mut ids,
519+
ids: &mut IdMap::default(),
521520
error_codes: shared.codes,
522521
edition: shared.edition(),
523522
playground: &shared.playground,
524523
heading_offset: HeadingOffset::H1,
525524
}
526-
.into_string()
525+
.write_into(f))
527526
)
528527
}
529528

@@ -555,20 +554,18 @@ fn render_markdown(
555554
heading_offset: HeadingOffset,
556555
) -> impl fmt::Display {
557556
fmt::from_fn(move |f| {
558-
write!(
559-
f,
560-
"<div class=\"docblock\">{}</div>",
561-
Markdown {
562-
content: md_text,
563-
links: &links,
564-
ids: &mut cx.id_map.borrow_mut(),
565-
error_codes: cx.shared.codes,
566-
edition: cx.shared.edition(),
567-
playground: &cx.shared.playground,
568-
heading_offset,
569-
}
570-
.into_string()
571-
)
557+
f.write_str("<div class=\"docblock\">")?;
558+
Markdown {
559+
content: md_text,
560+
links: &links,
561+
ids: &mut cx.id_map.borrow_mut(),
562+
error_codes: cx.shared.codes,
563+
edition: cx.shared.edition(),
564+
playground: &cx.shared.playground,
565+
heading_offset,
566+
}
567+
.write_into(&mut *f)?;
568+
f.write_str("</div>")
572569
})
573570
}
574571

@@ -752,7 +749,7 @@ fn short_item_info(
752749
let mut id_map = cx.id_map.borrow_mut();
753750
let html = MarkdownItemInfo(note, &mut id_map);
754751
message.push_str(": ");
755-
message.push_str(&html.into_string());
752+
html.write_into(&mut message).unwrap();
756753
}
757754
extra_info.push(ShortItemInfo::Deprecation { message });
758755
}

src/librustdoc/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
html_playground_url = "https://play.rust-lang.org/"
44
)]
55
#![feature(rustc_private)]
6-
#![feature(ascii_char)]
76
#![feature(ascii_char_variants)]
7+
#![feature(ascii_char)]
88
#![feature(assert_matches)]
99
#![feature(box_patterns)]
1010
#![feature(debug_closure_helpers)]
@@ -13,6 +13,7 @@
1313
#![feature(if_let_guard)]
1414
#![feature(impl_trait_in_assoc_type)]
1515
#![feature(iter_intersperse)]
16+
#![feature(min_specialization)]
1617
#![feature(never_type)]
1718
#![feature(round_char_boundary)]
1819
#![feature(test)]

src/librustdoc/markdown.rs

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//!
99
//! [docs]: https://doc.rust-lang.org/stable/rustdoc/#using-standalone-markdown-files
1010
11-
use std::fmt::Write as _;
11+
use std::fmt::{self, Write as _};
1212
use std::fs::{File, create_dir_all, read_to_string};
1313
use std::io::prelude::*;
1414
use std::path::Path;
@@ -77,32 +77,33 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
7777
}
7878
let title = metadata[0];
7979

80-
let mut ids = IdMap::new();
8180
let error_codes = ErrorCodes::from(options.unstable_features.is_nightly_build());
82-
let text = if !options.markdown_no_toc {
83-
MarkdownWithToc {
84-
content: text,
85-
links: &[],
86-
ids: &mut ids,
87-
error_codes,
88-
edition,
89-
playground: &playground,
90-
}
91-
.into_string()
92-
} else {
93-
Markdown {
94-
content: text,
95-
links: &[],
96-
ids: &mut ids,
97-
error_codes,
98-
edition,
99-
playground: &playground,
100-
heading_offset: HeadingOffset::H1,
81+
let text = fmt::from_fn(|f| {
82+
if !options.markdown_no_toc {
83+
MarkdownWithToc {
84+
content: text,
85+
links: &[],
86+
ids: &mut IdMap::new(),
87+
error_codes,
88+
edition,
89+
playground: &playground,
90+
}
91+
.write_into(f)
92+
} else {
93+
Markdown {
94+
content: text,
95+
links: &[],
96+
ids: &mut IdMap::new(),
97+
error_codes,
98+
edition,
99+
playground: &playground,
100+
heading_offset: HeadingOffset::H1,
101+
}
102+
.write_into(f)
101103
}
102-
.into_string()
103-
};
104+
});
104105

105-
let err = write!(
106+
let res = write!(
106107
&mut out,
107108
r#"<!DOCTYPE html>
108109
<html lang="en">
@@ -130,15 +131,10 @@ pub(crate) fn render_and_write<P: AsRef<Path>>(
130131
</body>
131132
</html>"#,
132133
title = Escape(title),
133-
css = css,
134134
in_header = options.external_html.in_header,
135135
before_content = options.external_html.before_content,
136-
text = text,
137136
after_content = options.external_html.after_content,
138137
);
139138

140-
match err {
141-
Err(e) => Err(format!("cannot write to `{output}`: {e}", output = output.display())),
142-
Ok(_) => Ok(()),
143-
}
139+
res.map_err(|e| format!("cannot write to `{output}`: {e}", output = output.display()))
144140
}

0 commit comments

Comments
 (0)