Skip to content

Commit a84be78

Browse files
committed
stop cloning html render context
1 parent 56e7678 commit a84be78

File tree

7 files changed

+249
-169
lines changed

7 files changed

+249
-169
lines changed

src/librustdoc/formats/renderer.rs

+66-26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use rustc_middle::ty::TyCtxt;
22
use rustc_span::Symbol;
33

4-
use crate::clean;
4+
use crate::clean::{self, Item};
55
use crate::config::RenderOptions;
66
use crate::error::Error;
77
use crate::formats::cache::Cache;
@@ -27,12 +27,19 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
2727
tcx: TyCtxt<'tcx>,
2828
) -> Result<(Self, clean::Crate), Error>;
2929

30-
/// Make a new renderer to render a child of the item currently being rendered.
31-
fn make_child_renderer(&self) -> Self;
32-
3330
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
3431
fn item(&mut self, item: clean::Item) -> Result<(), Error>;
3532

33+
/// Runs before rendering an item (not a module)
34+
fn before_item(&mut self, _item: &clean::Item) -> Result<(), Error> {
35+
Ok(())
36+
}
37+
38+
/// Runs after rendering an item (not a module)
39+
fn after_item(&mut self) -> Result<(), Error> {
40+
Ok(())
41+
}
42+
3643
/// Renders a module (should not handle recursing into children).
3744
fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error>;
3845

@@ -65,33 +72,66 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
6572
return Ok(());
6673
}
6774

68-
// Render the crate documentation
69-
let mut work = vec![(format_renderer.make_child_renderer(), krate.module)];
75+
enum WorkUnit {
76+
Module { item: Item, current_index: usize },
77+
Single(Item),
78+
}
79+
80+
let mut work_units: Vec<WorkUnit> =
81+
vec![WorkUnit::Module { item: krate.module, current_index: 0 }];
7082

7183
let unknown = Symbol::intern("<unknown item>");
72-
while let Some((mut cx, item)) = work.pop() {
73-
if item.is_mod() && T::RUN_ON_MODULE {
74-
// modules are special because they add a namespace. We also need to
75-
// recurse into the items of the module as well.
76-
let _timer =
77-
prof.generic_activity_with_arg("render_mod_item", item.name.unwrap().to_string());
78-
79-
cx.mod_item_in(&item)?;
80-
let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = *item.kind
81-
else { unreachable!() };
82-
for it in module.items {
83-
debug!("Adding {:?} to worklist", it.name);
84-
work.push((cx.make_child_renderer(), it));
84+
while let Some(work_unit) = work_units.pop() {
85+
match work_unit {
86+
WorkUnit::Module { item, current_index } if T::RUN_ON_MODULE => {
87+
let (clean::StrippedItem(box clean::ModuleItem(module)) | clean::ModuleItem(module)) = item.kind.as_ref()
88+
else { unreachable!() };
89+
90+
if current_index == 0 {
91+
// just enter the module
92+
format_renderer.mod_item_in(&item)?;
93+
}
94+
95+
if current_index < module.items.len() {
96+
// get the next item
97+
let next_item = module.items[current_index].clone();
98+
99+
// stay in the module
100+
work_units.push(WorkUnit::Module { item, current_index: current_index + 1 });
101+
102+
// push the next item
103+
if next_item.is_mod() {
104+
work_units.push(WorkUnit::Module { item: next_item, current_index: 0 });
105+
} else {
106+
work_units.push(WorkUnit::Single(next_item));
107+
}
108+
} else {
109+
// the last item of the module has been rendered
110+
// -> exit the module
111+
format_renderer.mod_item_out()?;
112+
}
85113
}
86-
87-
cx.mod_item_out()?;
88-
// FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special
89-
// cases. Use an explicit match instead.
90-
} else if item.name.is_some() && !item.is_extern_crate() {
91-
prof.generic_activity_with_arg("render_item", item.name.unwrap_or(unknown).as_str())
92-
.run(|| cx.item(item))?;
114+
// FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special
115+
// cases. Use an explicit match instead.
116+
WorkUnit::Module { item, .. } | WorkUnit::Single(item)
117+
if item.name.is_some() && !item.is_extern_crate() =>
118+
{
119+
// render the item
120+
prof.generic_activity_with_arg(
121+
"render_item",
122+
item.name.unwrap_or(unknown).as_str(),
123+
)
124+
.run(|| {
125+
format_renderer.before_item(&item)?;
126+
let result = format_renderer.item(item)?;
127+
format_renderer.after_item()?;
128+
Ok(result)
129+
})?;
130+
}
131+
_ => {}
93132
}
94133
}
134+
95135
prof.extra_verbose_generic_activity("renderer_after_krate", T::descr())
96136
.run(|| format_renderer.after_krate())
97137
}

0 commit comments

Comments
 (0)