summaryrefslogtreecommitdiffstats
path: root/src/librustdoc/html/render/type_layout.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/librustdoc/html/render/type_layout.rs')
-rw-r--r--src/librustdoc/html/render/type_layout.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
new file mode 100644
index 000000000..c9b95b1e6
--- /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!(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!(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())
+ })
+}