abi_stable/
type_layout.rs

1//! Types for modeling the layout of a datatype
2
3use std::{
4    cell::RefCell,
5    cmp::{Eq, PartialEq},
6    collections::HashSet,
7    fmt::{self, Debug, Display, Formatter},
8    mem::{self, ManuallyDrop},
9};
10
11use core_extensions::{matches, StringExt};
12
13use crate::{
14    abi_stability::{
15        extra_checks::{ExtraChecksStaticRef, StoredExtraChecks},
16        stable_abi_trait::AbiConsts,
17    },
18    const_utils::log2_usize,
19    prefix_type::{FieldAccessibility, FieldConditionality},
20    reflection::ModReflMode,
21    sabi_types::{CmpIgnored, NulStr, VersionStrings},
22    std_types::{RSlice, RStr, UTypeId},
23};
24
25mod construction;
26pub mod data_structures;
27mod iterators;
28mod printing;
29mod shared_vars;
30mod small_types;
31pub mod tagging;
32mod tl_data;
33mod tl_enums;
34mod tl_field;
35mod tl_fields;
36mod tl_functions;
37mod tl_lifetimes;
38mod tl_multi_tl;
39mod tl_other;
40mod tl_prefix;
41mod tl_reflection;
42
43pub(crate) use self::iterators::ChainOnce;
44
45pub use self::{
46    construction::{ItemInfo, _private_MonoTypeLayoutDerive, _private_TypeLayoutDerive},
47    shared_vars::{MonoSharedVars, SharedVars},
48    small_types::{OptionU16, OptionU8, StartLen, StartLenConverter, StartLenRepr},
49    tagging::Tag,
50    tl_data::{GenericTLData, MismatchedTLDataVariant, MonoTLData, TLData, TLDataDiscriminant},
51    tl_enums::{
52        DiscriminantRepr, GenericTLEnum, IncompatibleWithNonExhaustive, IsExhaustive,
53        MakeTLNonExhaustive, MonoTLEnum, TLDiscriminant, TLDiscriminants, TLEnum, TLNonExhaustive,
54    },
55    tl_field::{CompTLField, CompTLFieldRepr, TLField},
56    tl_fields::{CompTLFields, TLFields, TLFieldsIterator},
57    tl_functions::{
58        CompTLFunction, TLFunction, TLFunctionIter, TLFunctionQualifiers, TLFunctionSlice,
59        TLFunctions,
60    },
61    tl_lifetimes::{
62        LifetimeArrayOrSlice, LifetimeIndex, LifetimeIndexArray, LifetimeIndexPair,
63        LifetimeIndexPairRepr, LifetimeRange,
64    },
65    tl_multi_tl::{MTLIterator, MultipleTypeLayouts, TypeLayoutIndex, TypeLayoutRange},
66    tl_other::{
67        CompGenericParams, FmtFullType, GenericParams, ModPath, ReprAttr, TLFieldOrFunction,
68        TLPrimitive,
69    },
70    tl_prefix::{GenericTLPrefixType, MonoTLPrefixType, TLPrefixType},
71    tl_reflection::{CompFieldAccessor, FieldAccessor},
72};
73
74////////////////////////////////////////////////////////////////////////////////
75
76/// The layout of a type,
77/// also includes metadata about where the type was defined.
78#[repr(C)]
79#[derive(Copy, Clone, StableAbi)]
80// I am specifically applying this attribute to TypeLayout to make
81// ExtraChecks take less time checking its own layout.
82//
83// Also because checking the layout of TypeLayout is redundant,
84// since I have to trust that it's correct to be able to use it
85// to check the layout of anything(including itself).
86#[sabi(unsafe_sabi_opaque_fields)]
87pub struct TypeLayout {
88    shared_vars: &'static SharedVars,
89
90    /// The parts of the type layout that never change based on generic parameters.
91    mono: &'static MonoTypeLayout,
92
93    /// Whether the type uses non-zero value optimization,
94    /// if true then an `Option<Self>` implements StableAbi.
95    is_nonzero: bool,
96
97    /// The alignment of the type represented as (1 << self.alignment_power_of_two).
98    alignment_power_of_two: u8,
99
100    /// The size of the type
101    size: usize,
102
103    tag: Option<&'static Tag>,
104
105    data: GenericTLData,
106
107    /// A json-like data structure used to add extra checks.
108    extra_checks: CmpIgnored<Option<&'static ManuallyDrop<StoredExtraChecks>>>,
109
110    /// A function to get the unique identifier for some type
111    type_id: extern "C" fn() -> UTypeId,
112}
113
114unsafe impl Send for TypeLayout {}
115unsafe impl Sync for TypeLayout {}
116
117unsafe impl Send for MonoTypeLayout {}
118unsafe impl Sync for MonoTypeLayout {}
119
120///////////////////////////
121
122impl TypeLayout {
123    pub(crate) const fn from_std<T>(
124        shared_vars: &'static SharedVars,
125        mono: &'static MonoTypeLayout,
126        abi_consts: AbiConsts,
127        data: GenericTLData,
128    ) -> Self {
129        Self {
130            shared_vars,
131            mono,
132            is_nonzero: abi_consts.is_nonzero,
133            type_id: abi_consts.type_id.0,
134            alignment_power_of_two: log2_usize(mem::align_of::<T>()),
135            size: mem::size_of::<T>(),
136            data,
137            extra_checks: CmpIgnored::new(None),
138            tag: None,
139        }
140    }
141
142    #[doc(hidden)]
143    pub const fn from_derive<T>(p: _private_TypeLayoutDerive) -> Self {
144        Self {
145            shared_vars: p.shared_vars,
146            mono: p.mono,
147            is_nonzero: p.abi_consts.is_nonzero,
148            type_id: p.abi_consts.type_id.0,
149            alignment_power_of_two: log2_usize(mem::align_of::<T>()),
150            size: mem::size_of::<T>(),
151            data: p.data,
152            extra_checks: CmpIgnored::new(p.extra_checks),
153            tag: p.tag,
154        }
155    }
156
157    /// Gets the SharedVars of the type,
158    /// containing the slices that many types inside TypeLayout contain ranges into.
159    pub const fn shared_vars(&self) -> &'static SharedVars {
160        self.shared_vars
161    }
162
163    /// Gets a type used to print the type(ie:`Foo<'a,'b,u32,RString,1,2>`)
164    #[doc(hidden)]
165    pub fn full_type(&self) -> FmtFullType {
166        FmtFullType {
167            name: self.mono.name(),
168            generics: self.generics(),
169            primitive: self.mono.data.to_primitive(),
170            utypeid: self.get_utypeid(),
171        }
172    }
173
174    /// Gets the package and package version where the type was declared.
175    pub fn package_and_version(&self) -> (RStr<'static>, VersionStrings) {
176        let (package, version) = self.item_info().package_and_version();
177
178        (RStr::from_str(package), VersionStrings::new(version))
179    }
180
181    /// Gets the package where the type was declared.
182    pub fn package(&self) -> RStr<'static> {
183        let (package, _) = self.item_info().package_and_version();
184        RStr::from_str(package)
185    }
186
187    /// Gets the package version for the package where the type was declared.
188    pub fn package_version(&self) -> VersionStrings {
189        let (_, version) = self.item_info().package_and_version();
190        VersionStrings::new(version)
191    }
192
193    /// Gets which line the type was defined in.
194    pub const fn line(&self) -> u32 {
195        self.item_info().line
196    }
197
198    /// Gets the full path to the module where the type was defined.
199    pub const fn mod_path(&self) -> ModPath {
200        self.item_info().mod_path
201    }
202
203    /// Gets a trait object used to check extra properties about the type.
204    #[inline]
205    pub fn extra_checks(&self) -> Option<ExtraChecksStaticRef> {
206        self.extra_checks.value.map(|x| x.sabi_reborrow())
207    }
208
209    /// Gets the fields of the type.
210    ///
211    /// # Return value
212    ///
213    /// If this a:
214    ///
215    /// - primitive or opaque type:
216    ///     It returns `None`.
217    ///
218    /// - enum:
219    ///     It returns `Some()` with all the fields in the order that they were declared,
220    ///     ignoring variants.
221    ///
222    /// - structs/unions/prefix types:
223    ///     It returns `Some()` with all the fields in the order that they were declared.
224    ///
225    pub const fn get_fields(&self) -> Option<TLFields> {
226        match self.mono.get_fields() {
227            Some(fields) => Some(fields.expand(self.shared_vars)),
228            None => None,
229        }
230    }
231
232    /// Whether this is a prefix-type(module or vtable).
233    pub const fn is_prefix_kind(&self) -> bool {
234        matches!(self.data, GenericTLData::PrefixType { .. })
235    }
236
237    /// Gets the name of the type.
238    #[inline]
239    pub fn name(&self) -> &'static str {
240        self.mono.name()
241    }
242
243    /// Gets whether the type is a NonZero type,
244    /// which can be put in an `Option` while being ffi-safe.
245    #[inline]
246    pub const fn is_nonzero(&self) -> bool {
247        self.is_nonzero
248    }
249
250    #[doc(hidden)]
251    #[cfg(feature = "testing")]
252    pub const fn _set_is_nonzero(mut self, is_nonzero: bool) -> Self {
253        self.is_nonzero = is_nonzero;
254        self
255    }
256
257    #[doc(hidden)]
258    #[cfg(feature = "testing")]
259    pub const fn _set_extra_checks(
260        mut self,
261        extra_checks: CmpIgnored<Option<&'static ManuallyDrop<StoredExtraChecks>>>,
262    ) -> Self {
263        self.extra_checks = extra_checks;
264        self
265    }
266
267    #[doc(hidden)]
268    #[cfg(feature = "testing")]
269    pub const fn _set_type_id(mut self, type_id: extern "C" fn() -> UTypeId) -> Self {
270        self.type_id = type_id;
271        self
272    }
273
274    /// Gets the `UTypeId` for the type,
275    /// which is an ffi safe equivalent of `TypeId`.
276    #[inline]
277    pub fn get_utypeid(&self) -> UTypeId {
278        (self.type_id)()
279    }
280
281    /// Gets information about where a type was declared.
282    #[inline]
283    pub const fn item_info(&self) -> &ItemInfo {
284        self.mono.item_info()
285    }
286
287    /// Gets the alignment of the type.
288    #[inline]
289    pub const fn alignment(&self) -> usize {
290        1_usize << (self.alignment_power_of_two as u32)
291    }
292
293    /// Gets the size of the type.
294    #[inline]
295    pub const fn size(&self) -> usize {
296        self.size
297    }
298
299    /// Gets the `Tag` associated with a type,
300    /// a JSON-like datastructure which is another way to
301    /// check extra properties about a type.
302    pub const fn tag(&self) -> &'static Tag {
303        match self.tag {
304            Some(x) => x,
305            None => Tag::NULL,
306        }
307    }
308
309    /// Gets the representation attribute of the type.
310    pub const fn repr_attr(&self) -> ReprAttr {
311        self.mono.repr_attr()
312    }
313
314    /// Gets the `ModReflMode` for the type,
315    /// whether this is a module whose definition can be reflected on at runtime.
316    pub const fn mod_refl_mode(&self) -> ModReflMode {
317        self.mono.mod_refl_mode()
318    }
319
320    /// The interior of the type definition,
321    /// describing whether the type is a primitive/enum/struct/union and its contents.
322    pub fn data(&self) -> TLData {
323        self.mono
324            .data
325            .expand(self.data, self.shared_vars)
326            .unwrap_or_else(|e| {
327                panic!("\nError inside of '{}' type \n{}", self.full_type(), e);
328            })
329    }
330
331    /// Describes whether the type is a primitive/enum/struct/union,
332    /// every variant corresponds to a `TLData` variant of the same name.
333    pub const fn data_discriminant(&self) -> TLDataDiscriminant {
334        self.mono.data.as_discriminant()
335    }
336
337    /// Gets the virtual fields that aren't part of th type definition,
338    /// but are checked as part of the type
339    #[inline]
340    pub fn phantom_fields(&self) -> TLFields {
341        unsafe {
342            let slice = std::slice::from_raw_parts(
343                self.mono.phantom_fields,
344                self.mono.phantom_fields_len as usize,
345            );
346            TLFields::from_fields(slice, self.shared_vars)
347        }
348    }
349
350    /// Gets the generic parameters of the type.
351    pub fn generics(&self) -> GenericParams {
352        self.mono.generics.expand(self.shared_vars)
353    }
354
355    /// Gets the parts of the type layout that don't change with generic parameters.
356    pub const fn mono_type_layout(&self) -> &MonoTypeLayout {
357        self.mono
358    }
359}
360
361impl PartialEq for TypeLayout {
362    fn eq(&self, other: &TypeLayout) -> bool {
363        self.get_utypeid() == other.get_utypeid()
364    }
365}
366
367impl Eq for TypeLayout {}
368
369////////////////////////////////////////////////////////////////////////////////
370
371/// The data in the type layout that does not depend on generic parameters.
372#[repr(C)]
373#[derive(Copy, Clone, StableAbi)]
374#[sabi(unsafe_sabi_opaque_fields)]
375pub struct MonoTypeLayout {
376    shared_vars: MonoSharedVars,
377
378    /// The name of the type.
379    name: *const u8,
380
381    /// Contains information about where the type was defined.
382    ///
383    item_info: CmpIgnored<ItemInfo>,
384
385    /// What kind of type this is,Primitive/Struct/Enum/PrefixType.
386    data: MonoTLData,
387    /// The generic parameters of the type
388    generics: CompGenericParams,
389
390    /// Phantom fields,which don't have a runtime component(they aren't stored anywhere),
391    /// and are checked in layout checking.
392    phantom_fields: *const CompTLField,
393    phantom_fields_len: u8,
394
395    /// The representation attribute(s) of the type.
396    repr_attr: ReprAttr,
397
398    /// How the type is treated when interpreted as a module.
399    mod_refl_mode: ModReflMode,
400
401    name_len: u16,
402}
403
404#[allow(clippy::too_many_arguments)]
405impl MonoTypeLayout {
406    pub(crate) const fn new(
407        shared_vars: MonoSharedVars,
408        name: RStr<'static>,
409        item_info: ItemInfo,
410        data: MonoTLData,
411        generics: CompGenericParams,
412        repr_attr: ReprAttr,
413        mod_refl_mode: ModReflMode,
414        phantom_fields: RSlice<'static, CompTLField>,
415    ) -> Self {
416        Self {
417            shared_vars,
418            name: name.as_ptr(),
419            name_len: name.len() as u16,
420            item_info: CmpIgnored::new(item_info),
421            data,
422            generics,
423            repr_attr,
424            mod_refl_mode,
425            phantom_fields: phantom_fields.as_ptr(),
426            phantom_fields_len: phantom_fields.len() as u8,
427        }
428    }
429
430    #[doc(hidden)]
431    pub const fn from_derive(p: _private_MonoTypeLayoutDerive) -> Self {
432        Self {
433            name: p.name.as_ptr(),
434            name_len: p.name.len() as u16,
435            phantom_fields: p.phantom_fields.as_ptr() as *const CompTLFieldRepr
436                as *const CompTLField,
437            phantom_fields_len: p.phantom_fields.len() as u8,
438            item_info: CmpIgnored::new(p.item_info),
439            data: p.data,
440            generics: p.generics,
441            repr_attr: p.repr_attr,
442            mod_refl_mode: p.mod_refl_mode,
443            shared_vars: p.shared_vars,
444        }
445    }
446
447    /// Gets the name of the type.
448    pub fn name(&self) -> &'static str {
449        unsafe {
450            let slic = std::slice::from_raw_parts(self.name, self.name_len as usize);
451            std::str::from_utf8_unchecked(slic)
452        }
453    }
454
455    /// Gets the representation attribute of the type.
456    pub const fn repr_attr(&self) -> ReprAttr {
457        self.repr_attr
458    }
459
460    /// Gets the `ModReflMode` for the type,
461    /// whether this is a module whose definition can be reflected on at runtime.
462    pub const fn mod_refl_mode(&self) -> ModReflMode {
463        self.mod_refl_mode
464    }
465
466    /// Gets information about where a type was declared.
467    pub const fn item_info(&self) -> &ItemInfo {
468        &self.item_info.value
469    }
470
471    /// Gets the SharedVars of the type,
472    /// containing the slices that many types inside TypeLayout contain ranges into.
473    pub const fn shared_vars(&self) -> &MonoSharedVars {
474        &self.shared_vars
475    }
476
477    /// Gets the SharedVars of the type,
478    /// containing the slices that many types inside TypeLayout contain ranges into.
479    ///
480    /// This was defined as a workaround for an internal compiler error in nightly.
481    pub const fn shared_vars_static(&'static self) -> &'static MonoSharedVars {
482        &self.shared_vars
483    }
484
485    /// Gets the compressed versions of the fields of the type.
486    ///
487    /// # Return value
488    ///
489    /// If this a:
490    ///
491    /// - primitive or opaque type:
492    ///     It returns `None`.
493    ///
494    /// - enum:
495    ///     It returns `Some()` with all the fields in the order that they were declared,
496    ///     ignoring variants.
497    ///
498    /// - structs/unions/prefix types:
499    ///     It returns `Some()` with all the fields in the order that they were declared.
500    ///
501    pub const fn get_fields(&self) -> Option<CompTLFields> {
502        match self.data {
503            MonoTLData::Primitive { .. } => None,
504            MonoTLData::Opaque => None,
505            MonoTLData::Struct { fields } => Some(fields),
506            MonoTLData::Union { fields } => Some(fields),
507            MonoTLData::Enum(tlenum) => Some(tlenum.fields),
508            MonoTLData::PrefixType(prefix) => Some(prefix.fields),
509        }
510    }
511
512    /// Gets an iterator over all the names of the fields in the type.
513    pub fn field_names(&self) -> impl ExactSizeIterator<Item = &'static str> + Clone + 'static {
514        self.get_fields()
515            .unwrap_or(CompTLFields::EMPTY)
516            .field_names(&self.shared_vars)
517    }
518
519    /// Gets the name of the `nth` field in the type.
520    /// Returns `None` if there is no `nth` field.
521    pub fn get_field_name(&self, nth: usize) -> Option<&'static str> {
522        self.get_fields()
523            .unwrap_or(CompTLFields::EMPTY)
524            .get_field_name(nth, &self.shared_vars)
525    }
526}
527
528impl Debug for MonoTypeLayout {
529    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
530        f.debug_struct("MonoTypeLayout")
531            .field("name", &self.name())
532            .field("item_info", self.item_info())
533            .field("repr_attr", &self.repr_attr())
534            .field("mod_refl_mode", &self.mod_refl_mode())
535            .finish()
536    }
537}