Skip to content

Commit 11149af

Browse files
committed
Use template struct for item_struct
1 parent 1e51b81 commit 11149af

File tree

2 files changed

+226
-129
lines changed

2 files changed

+226
-129
lines changed

src/librustdoc/html/render/print_item.rs

Lines changed: 218 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,11 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
13671367
write!(w, "{name}({})", print_tuple_struct_fields(cx, s),);
13681368
}
13691369
clean::VariantKind::Struct(ref s) => {
1370-
render_struct(w, v, None, None, &s.fields, " ", false, cx);
1370+
write!(
1371+
w,
1372+
"{}",
1373+
render_struct(v, None, None, &s.fields, " ", false, cx)
1374+
);
13711375
}
13721376
},
13731377
_ => unreachable!(),
@@ -1585,53 +1589,123 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
15851589
}
15861590

15871591
fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) {
1588-
wrap_item(w, |w| {
1589-
write!(w, "{}", render_attributes_in_code(it, cx.tcx()));
1590-
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
1591-
});
1592+
#[derive(Template)]
1593+
#[template(path = "item_struct.html")]
1594+
struct ItemStruct<'a, 'cx> {
1595+
cx: std::cell::RefCell<&'a mut Context<'cx>>,
1596+
it: &'a clean::Item,
1597+
s: &'a clean::Struct,
1598+
}
15921599

1593-
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
1600+
impl<'a, 'cx: 'a> ItemStruct<'a, 'cx> {
1601+
fn render_attributes_in_code<'b>(
1602+
&'b self,
1603+
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
1604+
display_fn(move |f| {
1605+
let tcx = self.cx.borrow().tcx();
1606+
write!(f, "{}", render_attributes_in_code(self.it, tcx))
1607+
})
1608+
}
15941609

1595-
let mut fields = s
1596-
.fields
1597-
.iter()
1598-
.filter_map(|f| match *f.kind {
1599-
clean::StructFieldItem(ref ty) => Some((f, ty)),
1600-
_ => None,
1601-
})
1602-
.peekable();
1603-
if let None | Some(CtorKind::Fn) = s.ctor_kind {
1604-
if fields.peek().is_some() {
1605-
write!(
1606-
w,
1607-
"<h2 id=\"fields\" class=\"fields small-section-header\">\
1608-
{}{}<a href=\"#fields\" class=\"anchor\">§</a>\
1609-
</h2>\
1610-
{}",
1611-
if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
1612-
document_non_exhaustive_header(it),
1613-
document_non_exhaustive(it)
1614-
);
1615-
for (index, (field, ty)) in fields.enumerate() {
1616-
let field_name =
1617-
field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
1618-
let id = cx.derive_id(format!("{}.{}", ItemType::StructField, field_name));
1619-
write!(
1620-
w,
1621-
"<span id=\"{id}\" class=\"{item_type} small-section-header\">\
1622-
<a href=\"#{id}\" class=\"anchor field\">§</a>\
1623-
<code>{field_name}: {ty}</code>\
1624-
</span>",
1625-
item_type = ItemType::StructField,
1626-
ty = ty.print(cx)
1610+
fn render_struct<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
1611+
display_fn(move |f| {
1612+
let cx = self.cx.borrow();
1613+
let v = render_struct(
1614+
self.it,
1615+
Some(&self.s.generics),
1616+
self.s.ctor_kind,
1617+
&self.s.fields,
1618+
"",
1619+
true,
1620+
*cx,
16271621
);
1628-
write!(w, "{}", document(cx, field, Some(it), HeadingOffset::H3));
1629-
}
1622+
write!(f, "{v}")
1623+
})
1624+
}
1625+
1626+
fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
1627+
display_fn(move |f| {
1628+
let mut cx = self.cx.borrow_mut();
1629+
let v = document(*cx, self.it, None, HeadingOffset::H2);
1630+
write!(f, "{v}")
1631+
})
1632+
}
1633+
1634+
fn render_fields<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
1635+
display_fn(move |f| {
1636+
let mut fields = self
1637+
.s
1638+
.fields
1639+
.iter()
1640+
.filter_map(|f| match *f.kind {
1641+
clean::StructFieldItem(ref ty) => Some((f, ty)),
1642+
_ => None,
1643+
})
1644+
.peekable();
1645+
if let None | Some(CtorKind::Fn) = self.s.ctor_kind {
1646+
if fields.peek().is_some() {
1647+
write!(
1648+
f,
1649+
"<h2 id=\"fields\" class=\"fields small-section-header\">\
1650+
{}{}<a href=\"#fields\" class=\"anchor\">§</a>\
1651+
</h2>\
1652+
{}",
1653+
if self.s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
1654+
document_non_exhaustive_header(self.it),
1655+
document_non_exhaustive(self.it)
1656+
)?;
1657+
let mut cx = self.cx.borrow_mut();
1658+
for (index, (field, ty)) in fields.enumerate() {
1659+
let field_name = field
1660+
.name
1661+
.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
1662+
let id =
1663+
cx.derive_id(format!("{}.{}", ItemType::StructField, field_name));
1664+
write!(
1665+
f,
1666+
"<span id=\"{id}\" class=\"{item_type} small-section-header\">\
1667+
<a href=\"#{id}\" class=\"anchor field\">§</a>\
1668+
<code>{field_name}: {ty}</code>\
1669+
</span>",
1670+
ty = ty.print(*cx),
1671+
item_type = ItemType::StructField,
1672+
)?;
1673+
write!(
1674+
f,
1675+
"{doc}",
1676+
doc = document(*cx, field, Some(self.it), HeadingOffset::H3),
1677+
)?;
1678+
}
1679+
}
1680+
}
1681+
Ok(())
1682+
})
1683+
}
1684+
1685+
fn render_assoc_items<'b>(
1686+
&'b self,
1687+
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
1688+
display_fn(move |f| {
1689+
let mut cx = self.cx.borrow_mut();
1690+
let def_id = self.it.item_id.expect_def_id();
1691+
let v = render_assoc_items(*cx, self.it, def_id, AssocItemRender::All);
1692+
write!(f, "{v}")
1693+
})
1694+
}
1695+
1696+
fn document_type_layout<'b>(
1697+
&'b self,
1698+
) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> {
1699+
display_fn(move |f| {
1700+
let cx = self.cx.borrow();
1701+
let def_id = self.it.item_id.expect_def_id();
1702+
let v = document_type_layout(*cx, def_id);
1703+
write!(f, "{v}")
1704+
})
16301705
}
16311706
}
1632-
let def_id = it.item_id.expect_def_id();
1633-
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
1634-
write!(w, "{}", document_type_layout(cx, def_id));
1707+
1708+
ItemStruct { cx: std::cell::RefCell::new(cx), it, s }.render_into(w).unwrap();
16351709
}
16361710

16371711
fn item_static(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) {
@@ -1869,107 +1943,122 @@ fn render_union<'a, 'cx: 'a>(
18691943
})
18701944
}
18711945

1872-
fn render_struct(
1873-
mut w: &mut Buffer,
1874-
it: &clean::Item,
1875-
g: Option<&clean::Generics>,
1946+
fn render_struct<'a, 'cx: 'a>(
1947+
it: &'a clean::Item,
1948+
g: Option<&'a clean::Generics>,
18761949
ty: Option<CtorKind>,
1877-
fields: &[clean::Item],
1878-
tab: &str,
1950+
fields: &'a [clean::Item],
1951+
tab: &'a str,
18791952
structhead: bool,
1880-
cx: &Context<'_>,
1881-
) {
1882-
let tcx = cx.tcx();
1883-
write!(
1884-
w,
1885-
"{}{}{}",
1886-
visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
1887-
if structhead { "struct " } else { "" },
1888-
it.name.unwrap()
1889-
);
1890-
if let Some(g) = g {
1891-
write!(w, "{}", g.print(cx))
1892-
}
1893-
match ty {
1894-
None => {
1895-
let where_displayed =
1896-
g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false);
1953+
cx: &'a Context<'cx>,
1954+
) -> impl fmt::Display + 'a + Captures<'cx> {
1955+
display_fn(move |mut f| {
1956+
let tcx = cx.tcx();
1957+
write!(
1958+
f,
1959+
"{}{}{}",
1960+
visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
1961+
if structhead { "struct " } else { "" },
1962+
it.name.unwrap()
1963+
)?;
18971964

1898-
// If there wasn't a `where` clause, we add a whitespace.
1899-
if !where_displayed {
1900-
w.write_str(" {");
1901-
} else {
1902-
w.write_str("{");
1903-
}
1904-
let count_fields =
1905-
fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
1906-
let has_visible_fields = count_fields > 0;
1907-
let toggle = should_hide_fields(count_fields);
1908-
if toggle {
1909-
toggle_open(&mut w, format_args!("{} fields", count_fields));
1910-
}
1911-
for field in fields {
1912-
if let clean::StructFieldItem(ref ty) = *field.kind {
1913-
write!(
1914-
w,
1915-
"\n{} {}{}: {},",
1916-
tab,
1917-
visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
1918-
field.name.unwrap(),
1919-
ty.print(cx),
1920-
);
1921-
}
1922-
}
1965+
if let Some(g) = g {
1966+
write!(f, "{}", g.print(cx))?;
1967+
}
19231968

1924-
if has_visible_fields {
1925-
if it.has_stripped_entries().unwrap() {
1926-
write!(w, "\n{} /* private fields */", tab);
1969+
match ty {
1970+
None => {
1971+
let mut buf = Buffer::html();
1972+
let where_displayed =
1973+
g.map(|g| print_where_clause_and_check(&mut buf, g, cx)).unwrap_or(false);
1974+
write!(f, "{}", buf.into_inner())?;
1975+
1976+
// If there wasn't a `where` clause, we add a whitespace.
1977+
if !where_displayed {
1978+
f.write_str(" {")?;
1979+
} else {
1980+
f.write_str("{")?;
19271981
}
1928-
write!(w, "\n{}", tab);
1929-
} else if it.has_stripped_entries().unwrap() {
1930-
write!(w, " /* private fields */ ");
1931-
}
1932-
if toggle {
1933-
toggle_close(&mut w);
1934-
}
1935-
w.write_str("}");
1936-
}
1937-
Some(CtorKind::Fn) => {
1938-
w.write_str("(");
1939-
for (i, field) in fields.iter().enumerate() {
1940-
if i > 0 {
1941-
w.write_str(", ");
1982+
1983+
let count_fields = fields
1984+
.iter()
1985+
.filter(|item| matches!(*item.kind, clean::StructFieldItem(..)))
1986+
.count();
1987+
let has_visible_fields = count_fields > 0;
1988+
let toggle = should_hide_fields(count_fields);
1989+
if toggle {
1990+
toggle_open(&mut f, format_args!("{} fields", count_fields));
19421991
}
1943-
match *field.kind {
1944-
clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
1945-
clean::StructFieldItem(ref ty) => {
1992+
for field in fields {
1993+
if let clean::StructFieldItem(ref ty) = *field.kind {
19461994
write!(
1947-
w,
1948-
"{}{}",
1995+
f,
1996+
"\n{} {}{}: {},",
1997+
tab,
19491998
visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
1999+
field.name.unwrap(),
19502000
ty.print(cx),
1951-
)
2001+
)?;
19522002
}
1953-
_ => unreachable!(),
19542003
}
2004+
2005+
if has_visible_fields {
2006+
if it.has_stripped_entries().unwrap() {
2007+
write!(f, "\n{} /* private fields */", tab)?;
2008+
}
2009+
write!(f, "\n{}", tab)?;
2010+
} else if it.has_stripped_entries().unwrap() {
2011+
write!(f, " /* private fields */ ")?;
2012+
}
2013+
if toggle {
2014+
toggle_close(&mut f);
2015+
}
2016+
f.write_str("}")?;
19552017
}
1956-
w.write_str(")");
1957-
if let Some(g) = g {
1958-
write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
1959-
}
1960-
// We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
1961-
if structhead {
1962-
w.write_str(";");
2018+
Some(CtorKind::Fn) => {
2019+
write!(f, "(")?;
2020+
for (i, field) in fields.iter().enumerate() {
2021+
if i > 0 {
2022+
write!(f, ", ")?;
2023+
}
2024+
match *field.kind {
2025+
clean::StrippedItem(box clean::StructFieldItem(..)) => {
2026+
write!(f, "_")?;
2027+
}
2028+
clean::StructFieldItem(ref ty) => {
2029+
write!(
2030+
f,
2031+
"{}{}",
2032+
visibility_print_with_space(
2033+
field.visibility(tcx),
2034+
field.item_id,
2035+
cx
2036+
),
2037+
ty.print(cx),
2038+
)?;
2039+
}
2040+
_ => unreachable!(),
2041+
}
2042+
}
2043+
write!(f, ")")?;
2044+
if let Some(g) = g {
2045+
write!(f, "{}", print_where_clause(g, cx, 0, Ending::NoNewline))?;
2046+
}
2047+
// We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
2048+
if structhead {
2049+
write!(f, ";")?;
2050+
}
19632051
}
1964-
}
1965-
Some(CtorKind::Const) => {
1966-
// Needed for PhantomData.
1967-
if let Some(g) = g {
1968-
write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
2052+
Some(CtorKind::Const) => {
2053+
// Needed for PhantomData.
2054+
if let Some(g) = g {
2055+
write!(f, "{}", print_where_clause(g, cx, 0, Ending::NoNewline))?;
2056+
}
2057+
write!(f, ";")?;
19692058
}
1970-
w.write_str(";");
19712059
}
1972-
}
2060+
Ok(())
2061+
})
19732062
}
19742063

19752064
fn document_non_exhaustive_header(item: &clean::Item) -> &str {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<pre class="rust item-decl"><code>
2+
{{ self.render_attributes_in_code() | safe }}
3+
{{ self.render_struct() | safe }}
4+
</code></pre>
5+
{{ self.document() | safe }}
6+
{{ self.render_fields() | safe }}
7+
{{ self.render_assoc_items() | safe }}
8+
{{ self.document_type_layout() | safe }}

0 commit comments

Comments
 (0)