diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 0895bb510d481..77c2cd5b425d8 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -136,10 +136,6 @@ impl Buffer {
self.into_inner()
}
- pub(crate) fn is_for_html(&self) -> bool {
- self.for_html
- }
-
pub(crate) fn reserve(&mut self, additional: usize) {
self.buffer.reserve(additional)
}
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index d75d03071f892..1e3cd2668506f 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -50,6 +50,7 @@ use std::string::ToString;
use askama::Template;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
+use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::Mutability;
@@ -69,7 +70,7 @@ use crate::formats::item_type::ItemType;
use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape;
use crate::html::format::{
- href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
+ display_fn, 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,
Buffer, Ending, HrefError, PrintWithSpace,
};
@@ -408,128 +409,134 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
)
}
-fn document(
- w: &mut Buffer,
- cx: &mut Context<'_>,
- item: &clean::Item,
- parent: Option<&clean::Item>,
+fn document<'a, 'cx: 'a>(
+ cx: &'a mut Context<'cx>,
+ item: &'a clean::Item,
+ parent: Option<&'a clean::Item>,
heading_offset: HeadingOffset,
-) {
+) -> impl fmt::Display + 'a + Captures<'cx> {
if let Some(ref name) = item.name {
info!("Documenting {}", name);
}
- document_item_info(cx, item, parent).render_into(w).unwrap();
- if parent.is_none() {
- document_full_collapsible(w, item, cx, heading_offset);
- } else {
- document_full(w, item, cx, heading_offset);
- }
+
+ display_fn(move |f| {
+ document_item_info(cx, item, parent).render_into(f).unwrap();
+ if parent.is_none() {
+ write!(f, "{}", document_full_collapsible(item, cx, heading_offset))?;
+ } else {
+ write!(f, "{}", document_full(item, cx, heading_offset))?;
+ }
+ Ok(())
+ })
}
/// Render md_text as markdown.
-fn render_markdown(
- w: &mut Buffer,
- cx: &mut Context<'_>,
- md_text: &str,
+fn render_markdown<'a, 'cx: 'a>(
+ cx: &'a mut Context<'cx>,
+ md_text: &'a str,
links: Vec
` tag, it is formatted using
// a whitespace prefix and newline.
-fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
- for a in attributes(it) {
- writeln!(w, "{}{}", prefix, a);
- }
+fn render_attributes_in_pre<'a>(
+ it: &'a clean::Item,
+ prefix: &'a str,
+) -> impl fmt::Display + Captures<'a> {
+ crate::html::format::display_fn(move |f| {
+ for a in attributes(it) {
+ writeln!(f, "{}{}", prefix, a)?;
+ }
+ Ok(())
+ })
}
// When an attribute is rendered inside a tag, it is formatted using
@@ -1067,61 +1080,68 @@ impl<'a> AssocItemLink<'a> {
}
}
-fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
+fn write_impl_section_heading(mut w: impl fmt::Write, title: &str, id: &str) {
write!(
w,
"\
{title}\
§\
"
- );
+ )
+ .unwrap();
}
pub(crate) fn render_all_impls(
- w: &mut Buffer,
+ mut w: impl Write,
cx: &mut Context<'_>,
containing_item: &clean::Item,
concrete: &[&Impl],
synthetic: &[&Impl],
blanket_impl: &[&Impl],
) {
- let mut impls = Buffer::empty_from(w);
+ let mut impls = Buffer::html();
render_impls(cx, &mut impls, concrete, containing_item, true);
let impls = impls.into_inner();
if !impls.is_empty() {
- write_impl_section_heading(w, "Trait Implementations", "trait-implementations");
- write!(w, "{}", impls);
+ write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations");
+ write!(w, "{}", impls).unwrap();
}
if !synthetic.is_empty() {
- write_impl_section_heading(w, "Auto Trait Implementations", "synthetic-implementations");
- w.write_str("");
- render_impls(cx, w, synthetic, containing_item, false);
- w.write_str("");
+ write_impl_section_heading(
+ &mut w,
+ "Auto Trait Implementations",
+ "synthetic-implementations",
+ );
+ w.write_str("").unwrap();
+ render_impls(cx, &mut w, synthetic, containing_item, false);
+ w.write_str("").unwrap();
}
if !blanket_impl.is_empty() {
- write_impl_section_heading(w, "Blanket Implementations", "blanket-implementations");
- w.write_str("");
- render_impls(cx, w, blanket_impl, containing_item, false);
- w.write_str("");
+ write_impl_section_heading(&mut w, "Blanket Implementations", "blanket-implementations");
+ w.write_str("").unwrap();
+ render_impls(cx, &mut w, blanket_impl, containing_item, false);
+ w.write_str("").unwrap();
}
}
-fn render_assoc_items(
- w: &mut Buffer,
- cx: &mut Context<'_>,
- containing_item: &clean::Item,
+fn render_assoc_items<'a, 'cx: 'a>(
+ cx: &'a mut Context<'cx>,
+ containing_item: &'a clean::Item,
it: DefId,
- what: AssocItemRender<'_>,
-) {
+ what: AssocItemRender<'a>,
+) -> impl fmt::Display + 'a + Captures<'cx> {
let mut derefs = DefIdSet::default();
derefs.insert(it);
- render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
+ display_fn(move |f| {
+ render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
+ Ok(())
+ })
}
fn render_assoc_items_inner(
- w: &mut Buffer,
+ mut w: &mut dyn fmt::Write,
cx: &mut Context<'_>,
containing_item: &clean::Item,
it: DefId,
@@ -1134,7 +1154,7 @@ fn render_assoc_items_inner(
let Some(v) = cache.impls.get(&it) else { return };
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
if !non_trait.is_empty() {
- let mut tmp_buf = Buffer::empty_from(w);
+ let mut tmp_buf = Buffer::html();
let (render_mode, id) = match what {
AssocItemRender::All => {
write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
@@ -1158,7 +1178,7 @@ fn render_assoc_items_inner(
(RenderMode::ForDeref { mut_: deref_mut_ }, cx.derive_id(id))
}
};
- let mut impls_buf = Buffer::empty_from(w);
+ let mut impls_buf = Buffer::html();
for i in &non_trait {
render_impl(
&mut impls_buf,
@@ -1178,10 +1198,10 @@ fn render_assoc_items_inner(
);
}
if !impls_buf.is_empty() {
- w.push_buffer(tmp_buf);
- write!(w, "", id);
- w.push_buffer(impls_buf);
- w.write_str("");
+ write!(w, "{}", tmp_buf.into_inner()).unwrap();
+ write!(w, "", id).unwrap();
+ write!(w, "{}", impls_buf.into_inner()).unwrap();
+ w.write_str("").unwrap();
}
}
@@ -1191,7 +1211,7 @@ fn render_assoc_items_inner(
if let Some(impl_) = deref_impl {
let has_deref_mut =
traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
- render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
+ render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs);
}
// If we were already one level into rendering deref methods, we don't want to render
@@ -1210,7 +1230,7 @@ fn render_assoc_items_inner(
}
fn render_deref_methods(
- w: &mut Buffer,
+ mut w: impl Write,
cx: &mut Context<'_>,
impl_: &Impl,
container_item: &clean::Item,
@@ -1242,10 +1262,10 @@ fn render_deref_methods(
return;
}
}
- render_assoc_items_inner(w, cx, container_item, did, what, derefs);
+ render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
} else if let Some(prim) = target.primitive_type() {
if let Some(&did) = cache.primitive_locations.get(&prim) {
- render_assoc_items_inner(w, cx, container_item, did, what, derefs);
+ render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
}
}
}
@@ -1478,18 +1498,25 @@ fn render_impl(
document_item_info(cx, it, Some(parent))
.render_into(&mut info_buffer)
.unwrap();
- document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
+ write!(
+ &mut doc_buffer,
+ "{}",
+ document_full(item, cx, HeadingOffset::H5)
+ );
short_documented = false;
} else {
// In case the item isn't documented,
// provide short documentation from the trait.
- document_short(
+ write!(
&mut doc_buffer,
- it,
- cx,
- link,
- parent,
- rendering_params.show_def_docs,
+ "{}",
+ document_short(
+ it,
+ cx,
+ link,
+ parent,
+ rendering_params.show_def_docs,
+ )
);
}
}
@@ -1498,18 +1525,15 @@ fn render_impl(
.render_into(&mut info_buffer)
.unwrap();
if rendering_params.show_def_docs {
- document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
+ write!(&mut doc_buffer, "{}", document_full(item, cx, HeadingOffset::H5));
short_documented = false;
}
}
} else {
- document_short(
+ write!(
&mut doc_buffer,
- item,
- cx,
- link,
- parent,
- rendering_params.show_def_docs,
+ "{}",
+ document_short(item, cx, link, parent, rendering_params.show_def_docs,)
);
}
}
@@ -2206,7 +2230,7 @@ const MAX_FULL_EXAMPLES: usize = 5;
const NUM_VISIBLE_LINES: usize = 10;
/// Generates the HTML for example call locations generated via the --scrape-examples flag.
-fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item) {
+fn render_call_locations(mut w: W, cx: &mut Context<'_>, item: &clean::Item) {
let tcx = cx.tcx();
let def_id = item.item_id.expect_def_id();
let key = tcx.def_path_hash(def_id);
@@ -2215,7 +2239,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
// Generate a unique ID so users can link to this section for a given method
let id = cx.id_map.derive("scraped-examples");
write!(
- w,
+ &mut w,
"\
\
\
@@ -2224,7 +2248,8 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
",
root_path = cx.root_path(),
id = id
- );
+ )
+ .unwrap();
// Create a URL to a particular location in a reverse-dependency's source file
let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
@@ -2242,7 +2267,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
};
// Generate the HTML for a single example, being the title and code block
- let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
+ let write_example = |mut w: &mut W, (path, call_data): (&PathBuf, &CallData)| -> bool {
let contents = match fs::read_to_string(&path) {
Ok(contents) => contents,
Err(err) => {
@@ -2290,7 +2315,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
write!(
- w,
+ &mut w,
"\
\
{name} ({title})\
@@ -2303,10 +2328,12 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
// The locations are encoded as a data attribute, so they can be read
// later by the JS for interactions.
locations = Escape(&locations_encoded)
- );
+ )
+ .unwrap();
if line_ranges.len() > 1 {
- write!(w, r#" "#);
+ write!(w, r#" "#)
+ .unwrap();
}
// Look for the example file in the source map if it exists, otherwise return a dummy span
@@ -2333,7 +2360,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
decoration_info.insert("highlight", byte_ranges);
sources::print_src(
- w,
+ &mut w,
contents_subset,
file_span,
cx,
@@ -2341,7 +2368,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
highlight::DecorationInfo(decoration_info),
sources::SourceContext::Embedded { offset: line_min, needs_expansion },
);
- write!(w, "");
+ write!(w, "").unwrap();
true
};
@@ -2375,7 +2402,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
// An example may fail to write if its source can't be read for some reason, so this method
// continues iterating until a write succeeds
- let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
+ let write_and_skip_failure = |w: &mut W, it: &mut Peekable<_>| {
while let Some(example) = it.next() {
if write_example(&mut *w, example) {
break;
@@ -2384,7 +2411,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
};
// Write just one example that's visible by default in the method's description.
- write_and_skip_failure(w, &mut it);
+ write_and_skip_failure(&mut w, &mut it);
// Then add the remaining examples in a hidden section.
if it.peek().is_some() {
@@ -2397,17 +2424,19 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
Hide additional examples\
\
"
- );
+ )
+ .unwrap();
// Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
// make the page arbitrarily huge!
for _ in 0..MAX_FULL_EXAMPLES {
- write_and_skip_failure(w, &mut it);
+ write_and_skip_failure(&mut w, &mut it);
}
// For the remaining examples, generate a containing links to the source files.
if it.peek().is_some() {
- write!(w, r#"Additional examples can be found in:
"#);
+ write!(w, r#"Additional examples can be found in:
"#)
+ .unwrap();
it.for_each(|(_, call_data)| {
let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
write!(
@@ -2415,13 +2444,14 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
r#"- {name}
"#,
url = url,
name = call_data.display_name
- );
+ )
+ .unwrap();
});
- write!(w, "
");
+ write!(w, "
").unwrap();
}
- write!(w, "
");
+ write!(w, "").unwrap();
}
- write!(w, "");
+ write!(w, "").unwrap();
}
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 674cd0d62d49a..6bce57340040b 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -202,7 +202,7 @@ fn should_hide_fields(n_fields: usize) -> bool {
n_fields > 12
}
-fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
+fn toggle_open(mut w: impl fmt::Write, text: impl fmt::Display) {
write!(
w,
"\
@@ -210,15 +210,16 @@ fn toggle_open(w: &mut Buffer, text: impl fmt::Display) {
Show {}\
",
text
- );
+ )
+ .unwrap();
}
-fn toggle_close(w: &mut Buffer) {
- w.write_str("");
+fn toggle_close(mut w: impl fmt::Write) {
+ w.write_str("").unwrap();
}
fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: &[clean::Item]) {
- document(w, cx, item, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, item, None, HeadingOffset::H2));
let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::>();
@@ -544,12 +545,12 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));
wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
w.reserve(header_len);
write!(
w,
- "{vis}{constness}{asyncness}{unsafety}{abi}fn \
+ "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{notable_traits}{where_clause}",
+ attrs = render_attributes_in_pre(it, ""),
vis = visibility,
constness = constness,
asyncness = asyncness,
@@ -562,7 +563,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
notable_traits = notable_traits.unwrap_or_default(),
);
});
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
}
fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) {
@@ -580,17 +581,17 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone();
// Output the trait definition
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
+ wrap_item(w, |mut w| {
write!(
w,
- "{}{}{}trait {}{}{}",
+ "{attrs}{}{}{}trait {}{}{}",
visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
t.unsafety(tcx).print_with_space(),
if t.is_auto(tcx) { "auto " } else { "" },
it.name.unwrap(),
t.generics.print(cx),
- bounds
+ bounds,
+ attrs = render_attributes_in_pre(it, ""),
);
if !t.generics.where_predicates.is_empty() {
@@ -610,7 +611,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
if should_hide_fields(count_types) {
toggle = true;
toggle_open(
- w,
+ &mut w,
format_args!("{} associated items", count_types + count_consts + count_methods),
);
}
@@ -634,7 +635,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
if !toggle && should_hide_fields(count_types + count_consts) {
toggle = true;
toggle_open(
- w,
+ &mut w,
format_args!(
"{} associated constant{} and {} method{}",
count_consts,
@@ -662,7 +663,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
}
if !toggle && should_hide_fields(count_methods) {
toggle = true;
- toggle_open(w, format_args!("{} methods", count_methods));
+ toggle_open(&mut w, format_args!("{} methods", count_methods));
}
if count_consts != 0 && count_methods != 0 {
w.write_str("\n");
@@ -710,14 +711,14 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
}
}
if toggle {
- toggle_close(w);
+ toggle_close(&mut w);
}
w.write_str("}");
}
});
// Trait documentation
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) {
write!(
@@ -735,7 +736,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
let item_type = m.type_();
let id = cx.derive_id(format!("{}.{}", item_type, name));
let mut content = Buffer::empty_from(w);
- document(&mut content, cx, m, Some(t), HeadingOffset::H5);
+ write!(&mut content, "{}", document(cx, m, Some(t), HeadingOffset::H5));
let toggled = !content.is_empty();
if toggled {
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
@@ -847,7 +848,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
}
// If there are methods directly on this trait object, render them here.
- render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All);
+ write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All));
let cloned_shared = Rc::clone(&cx.shared);
let cache = &cloned_shared.cache;
@@ -1057,147 +1058,201 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) {
wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
write!(
w,
- "trait {}{}{} = {};",
+ "{attrs}trait {}{}{} = {};",
it.name.unwrap(),
t.generics.print(cx),
print_where_clause(&t.generics, cx, 0, Ending::Newline),
- bounds(&t.bounds, true, cx)
+ bounds(&t.bounds, true, cx),
+ attrs = render_attributes_in_pre(it, ""),
);
});
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
// Render any items associated directly to this alias, as otherwise they
// 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.
- render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
+ write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
}
fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) {
wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
write!(
w,
- "type {}{}{where_clause} = impl {bounds};",
+ "{attrs}type {}{}{where_clause} = impl {bounds};",
it.name.unwrap(),
t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
bounds = bounds(&t.bounds, false, cx),
+ attrs = render_attributes_in_pre(it, ""),
);
});
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
// Render any items associated directly to this alias, as otherwise they
// 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.
- render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
+ write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
}
fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) {
fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
write!(
w,
- "{}type {}{}{where_clause} = {type_};",
+ "{attrs}{}type {}{}{where_clause} = {type_};",
visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
it.name.unwrap(),
t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
type_ = t.type_.print(cx),
+ attrs = render_attributes_in_pre(it, ""),
);
});
}
write_content(w, cx, it, t);
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
let def_id = it.item_id.expect_def_id();
// Render any items associated directly to this alias, as otherwise they
// 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.
- render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
- document_type_layout(w, cx, def_id);
+ write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
+ write!(w, "{}", document_type_layout(cx, def_id));
}
fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) {
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
- render_union(w, it, Some(&s.generics), &s.fields, cx);
- });
+ #[derive(Template)]
+ #[template(path = "item_union.html")]
+ struct ItemUnion<'a, 'cx> {
+ cx: std::cell::RefCell<&'a mut Context<'cx>>,
+ it: &'a clean::Item,
+ s: &'a clean::Union,
+ }
- document(w, cx, it, None, HeadingOffset::H2);
+ impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> {
+ fn render_assoc_items<'b>(
+ &'b self,
+ ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let def_id = self.it.item_id.expect_def_id();
+ let mut cx = self.cx.borrow_mut();
+ let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All);
+ write!(f, "{v}")
+ })
+ }
+ fn document_type_layout<'b>(
+ &'b self,
+ ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let def_id = self.it.item_id.expect_def_id();
+ let cx = self.cx.borrow_mut();
+ let v = document_type_layout(*cx, def_id);
+ write!(f, "{v}")
+ })
+ }
+ fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let cx = self.cx.borrow_mut();
+ let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, *cx);
+ write!(f, "{v}")
+ })
+ }
+ fn render_attributes_in_pre<'b>(
+ &'b self,
+ ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let v = render_attributes_in_pre(self.it, "");
+ write!(f, "{v}")
+ })
+ }
+ fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let mut cx = self.cx.borrow_mut();
+ let v = document(*cx, self.it, None, HeadingOffset::H2);
+ write!(f, "{v}")
+ })
+ }
+ fn document_field<'b>(
+ &'b self,
+ field: &'a clean::Item,
+ ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let mut cx = self.cx.borrow_mut();
+ let v = document(*cx, field, Some(self.it), HeadingOffset::H3);
+ write!(f, "{v}")
+ })
+ }
+ fn stability_field(&self, field: &clean::Item) -> Option {
+ let cx = self.cx.borrow();
+ field.stability_class(cx.tcx())
+ }
+ fn print_ty<'b>(
+ &'b self,
+ ty: &'a clean::Type,
+ ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
+ display_fn(move |f| {
+ let cx = self.cx.borrow();
+ let v = ty.print(*cx);
+ write!(f, "{v}")
+ })
+ }
- let mut fields = s
- .fields
- .iter()
- .filter_map(|f| match *f.kind {
- clean::StructFieldItem(ref ty) => Some((f, ty)),
- _ => None,
- })
- .peekable();
- if fields.peek().is_some() {
- write!(
- w,
- "\
- Fields§\
-
"
- );
- for (field, ty) in fields {
- let name = field.name.expect("union field name");
- let id = format!("{}.{}", ItemType::StructField, name);
- write!(
- w,
- "\
- §\
- {name}: {ty}
\
- ",
- shortty = ItemType::StructField,
- ty = ty.print(cx),
- );
- if let Some(stability_class) = field.stability_class(cx.tcx()) {
- write!(w, "");
- }
- document(w, cx, field, Some(it), HeadingOffset::H3);
+ fn fields_iter(
+ &self,
+ ) -> std::iter::Peekable> {
+ self.s
+ .fields
+ .iter()
+ .filter_map(|f| match *f.kind {
+ clean::StructFieldItem(ref ty) => Some((f, ty)),
+ _ => None,
+ })
+ .peekable()
}
}
- let def_id = it.item_id.expect_def_id();
- render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
- document_type_layout(w, cx, def_id);
+
+ ItemUnion { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap();
}
-fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) {
- for (i, ty) in s.iter().enumerate() {
- if i > 0 {
- w.write_str(", ");
- }
- match *ty.kind {
- clean::StrippedItem(box clean::StructFieldItem(_)) => w.write_str("_"),
- clean::StructFieldItem(ref ty) => write!(w, "{}", ty.print(cx)),
- _ => unreachable!(),
+fn print_tuple_struct_fields<'a, 'cx: 'a>(
+ cx: &'a Context<'cx>,
+ s: &'a [clean::Item],
+) -> impl fmt::Display + 'a + Captures<'cx> {
+ display_fn(|f| {
+ for (i, ty) in s.iter().enumerate() {
+ if i > 0 {
+ f.write_str(", ")?;
+ }
+ match *ty.kind {
+ clean::StrippedItem(box clean::StructFieldItem(_)) => f.write_str("_")?,
+ clean::StructFieldItem(ref ty) => write!(f, "{}", ty.print(cx))?,
+ _ => unreachable!(),
+ }
}
- }
+ Ok(())
+ })
}
fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) {
let tcx = cx.tcx();
let count_variants = e.variants().count();
- wrap_item(w, |w| {
- render_attributes_in_pre(w, it, "");
+ wrap_item(w, |mut w| {
write!(
w,
- "{}enum {}{}",
+ "{attrs}{}enum {}{}",
visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
it.name.unwrap(),
e.generics.print(cx),
+ attrs = render_attributes_in_pre(it, ""),
);
if !print_where_clause_and_check(w, &e.generics, cx) {
// If there wasn't a `where` clause, we add a whitespace.
@@ -1211,7 +1266,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str("{\n");
let toggle = should_hide_fields(count_variants);
if toggle {
- toggle_open(w, format_args!("{} variants", count_variants));
+ toggle_open(&mut w, format_args!("{} variants", count_variants));
}
for v in e.variants() {
w.write_str(" ");
@@ -1221,9 +1276,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
clean::VariantItem(ref var) => match var.kind {
clean::VariantKind::CLike => write!(w, "{}", name),
clean::VariantKind::Tuple(ref s) => {
- write!(w, "{}(", name);
- print_tuple_struct_fields(w, cx, s);
- w.write_str(")");
+ write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
}
clean::VariantKind::Struct(ref s) => {
render_struct(w, v, None, None, &s.fields, " ", false, cx);
@@ -1238,24 +1291,25 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str(" // some variants omitted\n");
}
if toggle {
- toggle_close(w);
+ toggle_close(&mut w);
}
w.write_str("}");
}
});
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
if count_variants != 0 {
write!(
w,
"\
Variants{}§\
-
",
- document_non_exhaustive_header(it)
+ \
+ {}\
+ ",
+ document_non_exhaustive_header(it),
+ document_non_exhaustive(it)
);
- document_non_exhaustive(w, it);
- write!(w, "");
for variant in e.variants() {
let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
write!(
@@ -1276,9 +1330,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() };
if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
- w.write_str("(");
- print_tuple_struct_fields(w, cx, s);
- w.write_str(")");
+ write!(w, "({})", print_tuple_struct_fields(cx, s),);
}
w.write_str("");
@@ -1302,9 +1354,10 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
write!(
w,
"\
- {heading}
",
+ {heading}
\
+ {}",
+ document_non_exhaustive(variant)
);
- document_non_exhaustive(w, variant);
for field in fields {
match *field.kind {
clean::StrippedItem(box clean::StructFieldItem(_)) => {}
@@ -1322,10 +1375,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
{f}: {t}
\
",
f = field.name.unwrap(),
- t = ty.print(cx)
+ t = ty.print(cx),
+ );
+ write!(
+ w,
+ "{}",
+ document(cx, field, Some(variant), HeadingOffset::H5)
);
- document(w, cx, field, Some(variant), HeadingOffset::H5);
- write!(w, "");
}
_ => unreachable!(),
}
@@ -1333,18 +1389,18 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str("");
}
- document(w, cx, variant, Some(it), HeadingOffset::H4);
+ write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4));
}
write!(w, "");
}
let def_id = it.item_id.expect_def_id();
- render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
- document_type_layout(w, cx, def_id);
+ write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
+ write!(w, "{}", document_type_layout(cx, def_id));
}
fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
highlight::render_item_decl_with_highlighting(&t.source, w);
- document(w, cx, it, None, HeadingOffset::H2)
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
}
fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
@@ -1370,14 +1426,14 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c
}
}
});
- document(w, cx, it, None, HeadingOffset::H2)
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
}
fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
let def_id = it.item_id.expect_def_id();
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) {
- render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
+ write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
} else {
// We handle the "reference" primitive type on its own because we only want to list
// implementations on generic types.
@@ -1433,7 +1489,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
}
});
- document(w, cx, it, None, HeadingOffset::H2)
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
}
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
@@ -1442,7 +1498,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
});
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
let mut fields = s
.fields
@@ -1458,11 +1514,12 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
w,
"\
{}{}§\
-
",
+ \
+ {}",
if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
- document_non_exhaustive_header(it)
+ document_non_exhaustive_header(it),
+ document_non_exhaustive(it)
);
- document_non_exhaustive(w, it);
for (index, (field, ty)) in fields.enumerate() {
let field_name =
field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
@@ -1476,13 +1533,13 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
item_type = ItemType::StructField,
ty = ty.print(cx)
);
- document(w, cx, field, Some(it), HeadingOffset::H3);
+ write!(w, "{}", document(cx, field, Some(it), HeadingOffset::H3));
}
}
}
let def_id = it.item_id.expect_def_id();
- render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
- document_type_layout(w, cx, def_id);
+ write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
+ write!(w, "{}", document_type_layout(cx, def_id));
}
fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
@@ -1497,7 +1554,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
typ = s.type_.print(cx)
);
});
- document(w, cx, it, None, HeadingOffset::H2)
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
}
fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
@@ -1512,13 +1569,13 @@ fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
);
});
- document(w, cx, it, None, HeadingOffset::H2);
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
- render_assoc_items(w, cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
+ write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All))
}
fn item_keyword(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
- document(w, cx, it, None, HeadingOffset::H2)
+ write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
}
/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
@@ -1655,64 +1712,69 @@ fn render_implementor(
);
}
-fn render_union(
- w: &mut Buffer,
- it: &clean::Item,
- g: Option<&clean::Generics>,
- fields: &[clean::Item],
- cx: &Context<'_>,
-) {
- let tcx = cx.tcx();
- write!(
- w,
- "{}union {}",
- visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
- it.name.unwrap(),
- );
-
- let where_displayed = g
- .map(|g| {
- write!(w, "{}", g.print(cx));
- print_where_clause_and_check(w, g, cx)
- })
- .unwrap_or(false);
+fn render_union<'a, 'cx: 'a>(
+ it: &'a clean::Item,
+ g: Option<&'a clean::Generics>,
+ fields: &'a [clean::Item],
+ cx: &'a Context<'cx>,
+) -> impl fmt::Display + 'a + Captures<'cx> {
+ display_fn(move |mut f| {
+ let tcx = cx.tcx();
+ write!(
+ f,
+ "{}union {}",
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ it.name.unwrap(),
+ )?;
+
+ let where_displayed = g
+ .map(|g| {
+ let mut buf = Buffer::html();
+ write!(buf, "{}", g.print(cx));
+ let where_displayed = print_where_clause_and_check(&mut buf, g, cx);
+ write!(f, "{buf}", buf = buf.into_inner()).unwrap();
+ where_displayed
+ })
+ .unwrap_or(false);
- // If there wasn't a `where` clause, we add a whitespace.
- if !where_displayed {
- w.write_str(" ");
- }
+ // If there wasn't a `where` clause, we add a whitespace.
+ if !where_displayed {
+ f.write_str(" ")?;
+ }
- write!(w, "{{\n");
- let count_fields =
- fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
- let toggle = should_hide_fields(count_fields);
- if toggle {
- toggle_open(w, format_args!("{} fields", count_fields));
- }
+ write!(f, "{{\n")?;
+ let count_fields =
+ fields.iter().filter(|field| matches!(*field.kind, clean::StructFieldItem(..))).count();
+ let toggle = should_hide_fields(count_fields);
+ if toggle {
+ toggle_open(&mut f, format_args!("{} fields", count_fields));
+ }
- for field in fields {
- if let clean::StructFieldItem(ref ty) = *field.kind {
- write!(
- w,
- " {}{}: {},\n",
- visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
- field.name.unwrap(),
- ty.print(cx)
- );
+ for field in fields {
+ if let clean::StructFieldItem(ref ty) = *field.kind {
+ write!(
+ f,
+ " {}{}: {},\n",
+ visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
+ field.name.unwrap(),
+ ty.print(cx)
+ )?;
+ }
}
- }
- if it.has_stripped_entries().unwrap() {
- write!(w, " /* private fields */\n");
- }
- if toggle {
- toggle_close(w);
- }
- w.write_str("}");
+ if it.has_stripped_entries().unwrap() {
+ write!(f, " /* private fields */\n")?;
+ }
+ if toggle {
+ toggle_close(&mut f);
+ }
+ f.write_str("}").unwrap();
+ Ok(())
+ })
}
fn render_struct(
- w: &mut Buffer,
+ mut w: &mut Buffer,
it: &clean::Item,
g: Option<&clean::Generics>,
ty: Option,
@@ -1747,7 +1809,7 @@ fn render_struct(
let has_visible_fields = count_fields > 0;
let toggle = should_hide_fields(count_fields);
if toggle {
- toggle_open(w, format_args!("{} fields", count_fields));
+ toggle_open(&mut w, format_args!("{} fields", count_fields));
}
for field in fields {
if let clean::StructFieldItem(ref ty) = *field.kind {
@@ -1771,7 +1833,7 @@ fn render_struct(
write!(w, " /* private fields */ ");
}
if toggle {
- toggle_close(w);
+ toggle_close(&mut w);
}
w.write_str("}");
}
@@ -1817,161 +1879,169 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str {
if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" }
}
-fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) {
- if item.is_non_exhaustive() {
- write!(
- w,
- "\
- {}
\
- ",
- {
- if item.is_struct() {
- "This struct is marked as non-exhaustive"
- } else if item.is_enum() {
- "This enum is marked as non-exhaustive"
- } else if item.is_variant() {
- "This variant is marked as non-exhaustive"
- } else {
- "This type is marked as non-exhaustive"
+fn document_non_exhaustive<'a>(item: &'a clean::Item) -> impl fmt::Display + 'a {
+ display_fn(|f| {
+ if item.is_non_exhaustive() {
+ write!(
+ f,
+ "\
+ {}
\
+ ",
+ {
+ if item.is_struct() {
+ "This struct is marked as non-exhaustive"
+ } else if item.is_enum() {
+ "This enum is marked as non-exhaustive"
+ } else if item.is_variant() {
+ "This variant is marked as non-exhaustive"
+ } else {
+ "This type is marked as non-exhaustive"
+ }
}
+ )?;
+
+ if item.is_struct() {
+ f.write_str(
+ "Non-exhaustive structs could have additional fields added in future. \
+ Therefore, non-exhaustive structs cannot be constructed in external crates \
+ using the traditional Struct { .. }
syntax; cannot be \
+ matched against without a wildcard ..
; and \
+ struct update syntax will not work.",
+ )?;
+ } else if item.is_enum() {
+ f.write_str(
+ "Non-exhaustive enums could have additional variants added in future. \
+ Therefore, when matching against variants of non-exhaustive enums, an \
+ extra wildcard arm must be added to account for any future variants.",
+ )?;
+ } else if item.is_variant() {
+ f.write_str(
+ "Non-exhaustive enum variants could have additional fields added in future. \
+ Therefore, non-exhaustive enum variants cannot be constructed in external \
+ crates and cannot be matched against.",
+ )?;
+ } else {
+ f.write_str(
+ "This type will require a wildcard arm in any match statements or constructors.",
+ )?;
}
- );
- if item.is_struct() {
- w.write_str(
- "Non-exhaustive structs could have additional fields added in future. \
- Therefore, non-exhaustive structs cannot be constructed in external crates \
- using the traditional Struct { .. }
syntax; cannot be \
- matched against without a wildcard ..
; and \
- struct update syntax will not work.",
- );
- } else if item.is_enum() {
- w.write_str(
- "Non-exhaustive enums could have additional variants added in future. \
- Therefore, when matching against variants of non-exhaustive enums, an \
- extra wildcard arm must be added to account for any future variants.",
- );
- } else if item.is_variant() {
- w.write_str(
- "Non-exhaustive enum variants could have additional fields added in future. \
- Therefore, non-exhaustive enum variants cannot be constructed in external \
- crates and cannot be matched against.",
- );
- } else {
- w.write_str(
- "This type will require a wildcard arm in any match statements or constructors.",
- );
+ f.write_str("")?;
}
-
- w.write_str("");
- }
+ Ok(())
+ })
}
-fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
- fn write_size_of_layout(w: &mut Buffer, layout: &LayoutS, tag_size: u64) {
+fn document_type_layout<'a, 'cx: 'a>(
+ cx: &'a Context<'cx>,
+ ty_def_id: DefId,
+) -> impl fmt::Display + 'a + Captures<'cx> {
+ fn write_size_of_layout(mut w: impl fmt::Write, layout: &LayoutS, tag_size: u64) {
if layout.abi.is_unsized() {
- write!(w, "(unsized)");
+ write!(w, "(unsized)").unwrap();
} else {
let size = layout.size.bytes() - tag_size;
- write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" },);
+ write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" }).unwrap();
if layout.abi.is_uninhabited() {
write!(
w,
" (uninhabited)"
- );
+ ).unwrap();
}
}
}
- if !cx.shared.show_type_layout {
- return;
- }
-
- writeln!(
- w,
- " \
- Layout§
"
- );
- writeln!(w, "");
-
- let tcx = cx.tcx();
- let param_env = tcx.param_env(ty_def_id);
- let ty = tcx.type_of(ty_def_id).subst_identity();
- match tcx.layout_of(param_env.and(ty)) {
- Ok(ty_layout) => {
- writeln!(
- w,
- "Note: Most layout information is \
- completely unstable and may even differ between compilations. \
- The only exception is types with certain repr(...)
attributes. \
- Please see the Rust Reference’s \
- “Type Layout” \
- chapter for details on type layout guarantees.
"
- );
- w.write_str("Size: ");
- write_size_of_layout(w, &ty_layout.layout.0, 0);
- writeln!(w, "
");
- if let Variants::Multiple { variants, tag, tag_encoding, .. } =
- &ty_layout.layout.variants()
- {
- if !variants.is_empty() {
- w.write_str(
- "Size for each variant:
\
- ",
- );
-
- let Adt(adt, _) = ty_layout.ty.kind() else {
- span_bug!(tcx.def_span(ty_def_id), "not an adt")
- };
+ display_fn(move |mut f| {
+ if !cx.shared.show_type_layout {
+ return Ok(());
+ }
- let tag_size = if let TagEncoding::Niche { .. } = tag_encoding {
- 0
- } else if let Primitive::Int(i, _) = tag.primitive() {
- i.size().bytes()
- } else {
- span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int")
- };
+ writeln!(
+ f,
+ " \
+ Layout§
"
+ )?;
+ writeln!(f, "")?;
- for (index, layout) in variants.iter_enumerated() {
- let name = adt.variant(index).name;
- write!(w, "{name}
: ");
- write_size_of_layout(w, layout, tag_size);
- writeln!(w, " ");
+ let tcx = cx.tcx();
+ let param_env = tcx.param_env(ty_def_id);
+ let ty = tcx.type_of(ty_def_id).subst_identity();
+ match tcx.layout_of(param_env.and(ty)) {
+ Ok(ty_layout) => {
+ writeln!(
+ f,
+ "Note: Most layout information is \
+ completely unstable and may even differ between compilations. \
+ The only exception is types with certain repr(...)
attributes. \
+ Please see the Rust Reference’s \
+ “Type Layout” \
+ chapter for details on type layout guarantees.
"
+ )?;
+ f.write_str("Size: ")?;
+ write_size_of_layout(&mut f, &ty_layout.layout.0, 0);
+ writeln!(f, "
")?;
+ if let Variants::Multiple { variants, tag, tag_encoding, .. } =
+ &ty_layout.layout.variants()
+ {
+ if !variants.is_empty() {
+ f.write_str(
+ "Size for each variant:
\
+ ",
+ )?;
+
+ let Adt(adt, _) = ty_layout.ty.kind() else {
+ span_bug!(tcx.def_span(ty_def_id), "not an adt")
+ };
+
+ let tag_size = if let TagEncoding::Niche { .. } = tag_encoding {
+ 0
+ } else if let Primitive::Int(i, _) = tag.primitive() {
+ i.size().bytes()
+ } else {
+ span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int")
+ };
+
+ for (index, layout) in variants.iter_enumerated() {
+ let name = adt.variant(index).name;
+ write!(&mut f, "{name}
: ")?;
+ write_size_of_layout(&mut f, layout, tag_size);
+ writeln!(&mut f, " ")?;
+ }
+ f.write_str("
")?;
}
- w.write_str("");
}
}
+ // This kind of layout error can occur with valid code, e.g. if you try to
+ // get the layout of a generic type such as `Vec`.
+ Err(LayoutError::Unknown(_)) => {
+ writeln!(
+ f,
+ "Note: Unable to compute type layout, \
+ possibly due to this type having generic parameters. \
+ Layout can only be computed for concrete, fully-instantiated types.
"
+ )?;
+ }
+ // This kind of error probably can't happen with valid code, but we don't
+ // want to panic and prevent the docs from building, so we just let the
+ // user know that we couldn't compute the layout.
+ Err(LayoutError::SizeOverflow(_)) => {
+ writeln!(
+ f,
+ "Note: Encountered an error during type layout; \
+ the type was too big.
"
+ )?;
+ }
+ Err(LayoutError::NormalizationFailure(_, _)) => {
+ writeln!(
+ f,
+ "Note: Encountered an error during type layout; \
+ the type failed to be normalized.
"
+ )?;
+ }
}
- // This kind of layout error can occur with valid code, e.g. if you try to
- // get the layout of a generic type such as `Vec`.
- Err(LayoutError::Unknown(_)) => {
- writeln!(
- w,
- "Note: Unable to compute type layout, \
- possibly due to this type having generic parameters. \
- Layout can only be computed for concrete, fully-instantiated types.
"
- );
- }
- // This kind of error probably can't happen with valid code, but we don't
- // want to panic and prevent the docs from building, so we just let the
- // user know that we couldn't compute the layout.
- Err(LayoutError::SizeOverflow(_)) => {
- writeln!(
- w,
- "Note: Encountered an error during type layout; \
- the type was too big.
"
- );
- }
- Err(LayoutError::NormalizationFailure(_, _)) => {
- writeln!(
- w,
- "Note: Encountered an error during type layout; \
- the type failed to be normalized.
"
- )
- }
- }
- writeln!(w, " ");
+ writeln!(f, "
")
+ })
}
fn pluralize(count: usize) -> &'static str {
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index 1d298f52f7588..c8397967c8791 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -2,7 +2,6 @@ use crate::clean;
use crate::docfs::PathError;
use crate::error::Error;
use crate::html::format;
-use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::layout;
use crate::html::render::Context;
@@ -17,6 +16,7 @@ use rustc_span::source_map::FileName;
use std::cell::RefCell;
use std::ffi::OsStr;
+use std::fmt;
use std::fs;
use std::ops::RangeInclusive;
use std::path::{Component, Path, PathBuf};
@@ -294,7 +294,7 @@ pub(crate) enum SourceContext {
/// Wrapper struct to render the source code of a file. This will do things like
/// adding line numbers to the left-hand side.
pub(crate) fn print_src(
- buf: &mut Buffer,
+ mut writer: impl fmt::Write,
s: &str,
file_span: rustc_span::Span,
context: &Context<'_>,
@@ -329,5 +329,5 @@ pub(crate) fn print_src(
);
Ok(())
});
- Source { embedded, needs_expansion, lines, code_html: code }.render_into(buf).unwrap();
+ Source { embedded, needs_expansion, lines, code_html: code }.render_into(&mut writer).unwrap();
}
diff --git a/src/librustdoc/html/templates/item_union.html b/src/librustdoc/html/templates/item_union.html
new file mode 100644
index 0000000000000..a01457971c178
--- /dev/null
+++ b/src/librustdoc/html/templates/item_union.html
@@ -0,0 +1,23 @@
+
+ {{ self.render_attributes_in_pre() | safe }}
+ {{ self.render_union() | safe }}
+
+{{ self.document() | safe }}
+{% if self.fields_iter().peek().is_some() %}
+
+ Fields§
+
+ {% for (field, ty) in self.fields_iter() %}
+ {% let name = field.name.expect("union field name") %}
+
+ §
+ {{ name }}: {{ self.print_ty(ty) | safe }}
+
+ {% if let Some(stability_class) = self.stability_field(field) %}
+
+ {% endif %}
+ {{ self.document_field(field) | safe }}
+ {% endfor %}
+{% endif %}
+{{ self.render_assoc_items() | safe }}
+{{ self.document_type_layout() | safe }}