about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/html/render/mod.rs1
-rw-r--r--src/librustdoc/html/render/print_item.rs118
-rw-r--r--src/librustdoc/html/render/type_layout.rs86
-rw-r--r--src/librustdoc/html/templates/type_layout.html53
-rw-r--r--src/librustdoc/html/templates/type_layout_size.html12
5 files changed, 154 insertions, 116 deletions
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 463184acaa1..a5f08fdac11 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -32,6 +32,7 @@ mod context;
 mod print_item;
 mod sidebar;
 mod span_map;
+mod type_layout;
 mod write_shared;
 
 pub(crate) use self::context::*;
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 9a968e48b27..3e71d41ec96 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -6,16 +6,14 @@ use rustc_hir as hir;
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::stability;
-use rustc_middle::span_bug;
-use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{self, Adt, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_target::abi::{LayoutS, Primitive, TagEncoding, Variants};
 use std::cmp::Ordering;
 use std::fmt;
 use std::rc::Rc;
 
+use super::type_layout::document_type_layout;
 use super::{
     collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
     item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
@@ -1933,118 +1931,6 @@ fn document_non_exhaustive<'a>(item: &'a clean::Item) -> impl fmt::Display + 'a
     })
 }
 
-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)").unwrap();
-        } else {
-            let size = layout.size.bytes() - tag_size;
-            write!(w, "{size} byte{pl}", pl = if size == 1 { "" } else { "s" }).unwrap();
-            if layout.abi.is_uninhabited() {
-                write!(
-                    w,
-                    " (<a href=\"https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited\">uninhabited</a>)"
-                ).unwrap();
-            }
-        }
-    }
-
-    display_fn(move |mut f| {
-        if !cx.shared.show_type_layout {
-            return Ok(());
-        }
-
-        writeln!(
-            f,
-            "<h2 id=\"layout\" class=\"small-section-header\"> \
-            Layout<a href=\"#layout\" class=\"anchor\">§</a></h2>"
-        )?;
-        writeln!(f, "<div class=\"docblock\">")?;
-
-        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,
-                    "<div class=\"warning\"><p><strong>Note:</strong> Most layout information is \
-                    <strong>completely unstable</strong> and may even differ between compilations. \
-                    The only exception is types with certain <code>repr(...)</code> attributes. \
-                    Please see the Rust Reference’s \
-                    <a href=\"https://doc.rust-lang.org/reference/type-layout.html\">“Type Layout”</a> \
-                    chapter for details on type layout guarantees.</p></div>"
-                )?;
-                f.write_str("<p><strong>Size:</strong> ")?;
-                write_size_of_layout(&mut f, &ty_layout.layout.0, 0);
-                writeln!(f, "</p>")?;
-                if let Variants::Multiple { variants, tag, tag_encoding, .. } =
-                    &ty_layout.layout.variants()
-                {
-                    if !variants.is_empty() {
-                        f.write_str(
-                            "<p><strong>Size for each variant:</strong></p>\
-                                <ul>",
-                        )?;
-
-                        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, "<li><code>{name}</code>: ")?;
-                            write_size_of_layout(&mut f, layout, tag_size);
-                            writeln!(&mut f, "</li>")?;
-                        }
-                        f.write_str("</ul>")?;
-                    }
-                }
-            }
-            // 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<T>`.
-            Err(LayoutError::Unknown(_)) => {
-                writeln!(
-                    f,
-                    "<p><strong>Note:</strong> Unable to compute type layout, \
-                    possibly due to this type having generic parameters. \
-                    Layout can only be computed for concrete, fully-instantiated types.</p>"
-                )?;
-            }
-            // 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,
-                    "<p><strong>Note:</strong> Encountered an error during type layout; \
-                    the type was too big.</p>"
-                )?;
-            }
-            Err(LayoutError::NormalizationFailure(_, _)) => {
-                writeln!(
-                    f,
-                    "<p><strong>Note:</strong> Encountered an error during type layout; \
-                    the type failed to be normalized.</p>"
-                )?;
-            }
-        }
-
-        writeln!(f, "</div>")
-    })
-}
-
 fn pluralize(count: usize) -> &'static str {
     if count > 1 { "s" } else { "" }
 }
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
new file mode 100644
index 00000000000..22aec623335
--- /dev/null
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -0,0 +1,86 @@
+use askama::Template;
+
+use rustc_data_structures::captures::Captures;
+use rustc_hir::def_id::DefId;
+use rustc_middle::span_bug;
+use rustc_middle::ty::layout::LayoutError;
+use rustc_middle::ty::Adt;
+use rustc_span::symbol::Symbol;
+use rustc_target::abi::{Primitive, TagEncoding, Variants};
+
+use std::fmt;
+
+use crate::html::format::display_fn;
+use crate::html::render::Context;
+
+#[derive(Template)]
+#[template(path = "type_layout.html")]
+struct TypeLayout<'cx> {
+    variants: Vec<(Symbol, TypeLayoutSize)>,
+    type_layout_size: Result<TypeLayoutSize, LayoutError<'cx>>,
+}
+
+#[derive(Template)]
+#[template(path = "type_layout_size.html")]
+struct TypeLayoutSize {
+    is_unsized: bool,
+    is_uninhabited: bool,
+    size: u64,
+}
+
+pub(crate) fn document_type_layout<'a, 'cx: 'a>(
+    cx: &'a Context<'cx>,
+    ty_def_id: DefId,
+) -> impl fmt::Display + 'a + Captures<'cx> {
+    display_fn(move |f| {
+        if !cx.shared.show_type_layout {
+            return Ok(());
+        }
+
+        let tcx = cx.tcx();
+        let param_env = tcx.param_env(ty_def_id);
+        let ty = tcx.type_of(ty_def_id).subst_identity();
+        let type_layout = tcx.layout_of(param_env.and(ty));
+
+        let variants =
+            if let Ok(type_layout) = type_layout &&
+                let Variants::Multiple { variants, tag, tag_encoding, .. } =
+                    type_layout.layout.variants() &&
+                !variants.is_empty()
+            {
+                let tag_size =
+                    if let TagEncoding::Niche { .. } = tag_encoding {
+                        0
+                    } else if let Primitive::Int(i, _) = tag.primitive() {
+                        i.size().bytes()
+                    } else {
+                        span_bug!(cx.tcx().def_span(ty_def_id), "tag is neither niche nor int")
+                    };
+                variants
+                    .iter_enumerated()
+                    .map(|(variant_idx, variant_layout)| {
+                        let Adt(adt, _) = type_layout.ty.kind() else {
+                            span_bug!(cx.tcx().def_span(ty_def_id), "not an adt")
+                        };
+                        let name = adt.variant(variant_idx).name;
+                        let is_unsized = variant_layout.abi.is_unsized();
+                        let is_uninhabited = variant_layout.abi.is_uninhabited();
+                        let size = variant_layout.size.bytes() - tag_size;
+                        let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
+                        (name, type_layout_size)
+                    })
+                    .collect()
+            } else {
+                Vec::new()
+            };
+
+        let type_layout_size = tcx.layout_of(param_env.and(ty)).map(|layout| {
+            let is_unsized = layout.abi.is_unsized();
+            let is_uninhabited = layout.abi.is_uninhabited();
+            let size = layout.size.bytes();
+            TypeLayoutSize { is_unsized, is_uninhabited, size }
+        });
+
+        Ok(TypeLayout { variants, type_layout_size }.render_into(f).unwrap())
+    })
+}
diff --git a/src/librustdoc/html/templates/type_layout.html b/src/librustdoc/html/templates/type_layout.html
new file mode 100644
index 00000000000..58b220c7428
--- /dev/null
+++ b/src/librustdoc/html/templates/type_layout.html
@@ -0,0 +1,53 @@
+<h2 id="layout" class="small-section-header">  {# #}
+    Layout<a href="#layout" class="anchor">§</a> {# #}
+</h2> {# #}
+<div class="docblock"> {# #}
+    {% match type_layout_size %}
+        {% when Ok(type_layout_size) %}
+            <div class="warning"> {# #}
+                <p> {# #}
+                    <strong>Note:</strong> Most layout information is <strong>completely {#+ #}
+                    unstable</strong> and may even differ between compilations. {#+ #}
+                    The only exception is types with certain <code>repr(...)</code> {#+ #}
+                    attributes. Please see the Rust Reference’s {#+ #}
+                    <a href="https://doc.rust-lang.org/reference/type-layout.html">“Type Layout”</a> {#+ #}
+                    chapter for details on type layout guarantees. {# #}
+                </p> {# #}
+            </div> {# #}
+            <p><strong>Size:</strong> {{ type_layout_size|safe }}</p> {# #}
+            {% if !variants.is_empty() %}
+                <p> {# #}
+                    <strong>Size for each variant:</strong> {# #}
+                </p> {# #}
+                <ul> {# #}
+                    {% for (name, layout_size) in variants %}
+                        <li> {# #}
+                            <code>{{ name }}</code>: {#+ #}
+                            {{ layout_size|safe }}
+                        </li> {# #}
+                    {% endfor %}
+                </ul> {# #}
+            {% endif %}
+        {# 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<T>`. #}
+        {% when Err(LayoutError::Unknown(_)) %}
+            <p> {# #}
+                <strong>Note:</strong> Unable to compute type layout, {#+ #}
+                possibly due to this type having generic parameters. {#+ #}
+                Layout can only be computed for concrete, fully-instantiated types. {# #}
+            </p> {# #}
+        {# 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. #}
+        {% when Err(LayoutError::SizeOverflow(_)) %}
+            <p> {# #}
+                <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+                the type was too big. {# #}
+            </p> {# #}
+        {% when Err(LayoutError::NormalizationFailure(_, _)) %}
+            <p> {# #}
+                <strong>Note:</strong> Encountered an error during type layout; {#+ #}
+                the type failed to be normalized. {# #}
+            </p> {# #}
+    {% endmatch %}
+</div> {# #}
diff --git a/src/librustdoc/html/templates/type_layout_size.html b/src/librustdoc/html/templates/type_layout_size.html
new file mode 100644
index 00000000000..9c2b39edc9f
--- /dev/null
+++ b/src/librustdoc/html/templates/type_layout_size.html
@@ -0,0 +1,12 @@
+{% if is_unsized %}
+  (unsized)
+{% else %}
+  {% if size == 1 %}
+    1 byte
+  {% else %}
+    {{ size +}} bytes
+  {% endif %}
+  {% if is_uninhabited %}
+    {# +#} (<a href="https://doc.rust-lang.org/stable/reference/glossary.html#uninhabited">uninhabited</a>)
+  {% endif %}
+{% endif %}