1use std::fmt;
2use std::ops::Deref;
3
4use rustc_data_structures::intern::Interned;
5use rustc_macros::HashStable_Generic;
6
7use crate::{
8    AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
9    PointeeInfo, Primitive, Size, Variants,
10};
11
12rustc_index::newtype_index! {
15    #[derive(HashStable_Generic)]
37    #[encodable]
38    #[orderable]
39    pub struct FieldIdx {}
40}
41
42impl FieldIdx {
43    pub const ONE: FieldIdx = FieldIdx::from_u32(1);
47}
48
49rustc_index::newtype_index! {
50    #[derive(HashStable_Generic)]
61    #[encodable]
62    #[orderable]
63    pub struct VariantIdx {
64        const FIRST_VARIANT = 0;
66    }
67}
68#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
69#[rustc_pass_by_value]
70pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
71
72impl<'a> fmt::Debug for Layout<'a> {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        self.0.0.fmt(f)
76    }
77}
78
79impl<'a> Deref for Layout<'a> {
80    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
81    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
82        &self.0.0
83    }
84}
85
86impl<'a> Layout<'a> {
87    pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
88        &self.0.0.fields
89    }
90
91    pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
92        &self.0.0.variants
93    }
94
95    pub fn backend_repr(self) -> BackendRepr {
96        self.0.0.backend_repr
97    }
98
99    pub fn largest_niche(self) -> Option<Niche> {
100        self.0.0.largest_niche
101    }
102
103    pub fn align(self) -> AbiAlign {
104        self.0.0.align
105    }
106
107    pub fn size(self) -> Size {
108        self.0.0.size
109    }
110
111    pub fn max_repr_align(self) -> Option<Align> {
112        self.0.0.max_repr_align
113    }
114
115    pub fn unadjusted_abi_align(self) -> Align {
116        self.0.0.unadjusted_abi_align
117    }
118}
119
120#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
128pub struct TyAndLayout<'a, Ty> {
129    pub ty: Ty,
130    pub layout: Layout<'a>,
131}
132
133impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        f.debug_struct("TyAndLayout")
137            .field("ty", &format_args!("{}", self.ty))
138            .field("layout", &self.layout)
139            .finish()
140    }
141}
142
143impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
144    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
145    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
146        &self.layout.0.0
147    }
148}
149
150impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
151    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
152        &*self.layout.0.0
153    }
154}
155
156pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
159    fn ty_and_layout_for_variant(
160        this: TyAndLayout<'a, Self>,
161        cx: &C,
162        variant_index: VariantIdx,
163    ) -> TyAndLayout<'a, Self>;
164    fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
165    fn ty_and_layout_pointee_info_at(
166        this: TyAndLayout<'a, Self>,
167        cx: &C,
168        offset: Size,
169    ) -> Option<PointeeInfo>;
170    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
171    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
172    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
173    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
174    fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
175}
176
177impl<'a, Ty> TyAndLayout<'a, Ty> {
178    pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
179    where
180        Ty: TyAbiInterface<'a, C>,
181    {
182        Ty::ty_and_layout_for_variant(self, cx, variant_index)
183    }
184
185    pub fn field<C>(self, cx: &C, i: usize) -> Self
186    where
187        Ty: TyAbiInterface<'a, C>,
188    {
189        Ty::ty_and_layout_field(self, cx, i)
190    }
191
192    pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
193    where
194        Ty: TyAbiInterface<'a, C>,
195    {
196        Ty::ty_and_layout_pointee_info_at(self, cx, offset)
197    }
198
199    pub fn is_single_fp_element<C>(self, cx: &C) -> bool
200    where
201        Ty: TyAbiInterface<'a, C>,
202        C: HasDataLayout,
203    {
204        match self.backend_repr {
205            BackendRepr::Scalar(scalar) => {
206                matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64))
207            }
208            BackendRepr::Memory { .. } => {
209                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
210                    self.field(cx, 0).is_single_fp_element(cx)
211                } else {
212                    false
213                }
214            }
215            _ => false,
216        }
217    }
218
219    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
220    where
221        Ty: TyAbiInterface<'a, C>,
222        C: HasDataLayout,
223    {
224        match self.backend_repr {
225            BackendRepr::SimdVector { .. } => self.size == expected_size,
226            BackendRepr::Memory { .. } => {
227                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
228                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
229                } else {
230                    false
231                }
232            }
233            _ => false,
234        }
235    }
236
237    pub fn is_adt<C>(self) -> bool
238    where
239        Ty: TyAbiInterface<'a, C>,
240    {
241        Ty::is_adt(self)
242    }
243
244    pub fn is_never<C>(self) -> bool
245    where
246        Ty: TyAbiInterface<'a, C>,
247    {
248        Ty::is_never(self)
249    }
250
251    pub fn is_tuple<C>(self) -> bool
252    where
253        Ty: TyAbiInterface<'a, C>,
254    {
255        Ty::is_tuple(self)
256    }
257
258    pub fn is_unit<C>(self) -> bool
259    where
260        Ty: TyAbiInterface<'a, C>,
261    {
262        Ty::is_unit(self)
263    }
264
265    pub fn is_transparent<C>(self) -> bool
266    where
267        Ty: TyAbiInterface<'a, C>,
268    {
269        Ty::is_transparent(self)
270    }
271
272    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
275    where
276        Ty: TyAbiInterface<'a, C> + Copy,
277    {
278        let mut found = None;
279        for field_idx in 0..self.fields.count() {
280            let field = self.field(cx, field_idx);
281            if field.is_1zst() {
282                continue;
283            }
284            if found.is_some() {
285                return None;
287            }
288            found = Some((FieldIdx::from_usize(field_idx), field));
289        }
290        found
291    }
292}