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