diff options
Diffstat (limited to 'src/librustdoc/html/render/type_layout.rs')
-rw-r--r-- | src/librustdoc/html/render/type_layout.rs | 86 |
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()) + }) +} |