rustdoc/html/render/
type_layout.rs
1use std::fmt;
2
3use rinja::Template;
4use rustc_abi::{Primitive, TagEncoding, Variants};
5use rustc_hir::def_id::DefId;
6use rustc_middle::span_bug;
7use rustc_middle::ty::layout::LayoutError;
8use rustc_middle::ty::{self};
9use rustc_span::symbol::Symbol;
10
11use crate::html::render::Context;
12
13#[derive(Template)]
14#[template(path = "type_layout.html")]
15struct TypeLayout<'cx> {
16 variants: Vec<(Symbol, TypeLayoutSize)>,
17 type_layout_size: Result<TypeLayoutSize, &'cx LayoutError<'cx>>,
18}
19
20#[derive(Template)]
21#[template(path = "type_layout_size.html")]
22struct TypeLayoutSize {
23 is_unsized: bool,
24 is_uninhabited: bool,
25 size: u64,
26}
27
28pub(crate) fn document_type_layout(cx: &Context<'_>, ty_def_id: DefId) -> impl fmt::Display {
29 fmt::from_fn(move |f| {
30 if !cx.shared.show_type_layout {
31 return Ok(());
32 }
33
34 let tcx = cx.tcx();
35 let typing_env = ty::TypingEnv::post_analysis(tcx, ty_def_id);
36 let ty = tcx.type_of(ty_def_id).instantiate_identity();
37 let type_layout = tcx.layout_of(typing_env.as_query_input(ty));
38
39 let variants = if let Ok(type_layout) = type_layout
40 && let Variants::Multiple { variants, tag, tag_encoding, .. } =
41 type_layout.layout.variants()
42 && !variants.is_empty()
43 {
44 let tag_size = if let TagEncoding::Niche { .. } = tag_encoding {
45 0
46 } else if let Primitive::Int(i, _) = tag.primitive() {
47 i.size().bytes()
48 } else {
49 span_bug!(tcx.def_span(ty_def_id), "tag is neither niche nor int")
50 };
51 variants
52 .iter_enumerated()
53 .map(|(variant_idx, variant_layout)| {
54 let ty::Adt(adt, _) = type_layout.ty.kind() else {
55 span_bug!(tcx.def_span(ty_def_id), "not an adt")
56 };
57 let name = adt.variant(variant_idx).name;
58 let is_unsized = variant_layout.is_unsized();
59 let is_uninhabited = variant_layout.is_uninhabited();
60 let size = variant_layout.size.bytes() - tag_size;
61 let type_layout_size = TypeLayoutSize { is_unsized, is_uninhabited, size };
62 (name, type_layout_size)
63 })
64 .collect()
65 } else {
66 Vec::new()
67 };
68
69 let type_layout_size = tcx.layout_of(typing_env.as_query_input(ty)).map(|layout| {
70 let is_unsized = layout.is_unsized();
71 let is_uninhabited = layout.is_uninhabited();
72 let size = layout.size.bytes();
73 TypeLayoutSize { is_unsized, is_uninhabited, size }
74 });
75
76 TypeLayout { variants, type_layout_size }.render_into(f).unwrap();
77 Ok(())
78 })
79}