abi_stable/type_layout/
tl_enums.rs

1use super::*;
2
3use crate::{
4    abi_stability::abi_checking::{push_err, AbiInstability},
5    const_utils::log2_usize,
6    std_types::{RSlice, RString, RVec},
7};
8
9///////////////////////////
10
11/// The parts of the layout of an enum,that don't depend on generic parameters.
12#[repr(C)]
13#[derive(Copy, Clone, StableAbi)]
14#[sabi(unsafe_sabi_opaque_fields)]
15pub struct MonoTLEnum {
16    /// The amount of fields of each variant.
17    field_count: *const u8,
18    field_count_len: u16,
19
20    /// A ';' separated list of all variant names
21    variant_names: StartLen,
22
23    /// All the fields of the enums,not separated by variant.
24    pub(super) fields: CompTLFields,
25}
26
27unsafe impl Sync for MonoTLEnum {}
28unsafe impl Send for MonoTLEnum {}
29
30impl MonoTLEnum {
31    /// Constructs a `MonoTLEnum`.
32    pub const fn new(
33        variant_names: StartLen,
34        field_count: RSlice<'static, u8>,
35        fields: CompTLFields,
36    ) -> Self {
37        Self {
38            field_count: field_count.as_ptr(),
39            field_count_len: field_count.len() as u16,
40            variant_names,
41            fields,
42        }
43    }
44
45    /// Gets the amount of variants in the enum.
46    pub const fn variant_count(&self) -> usize {
47        self.field_count_len as usize
48    }
49
50    /// Gets a slice with the amount of fields for each variant in the enum.
51    pub const fn field_count(&self) -> RSlice<'static, u8> {
52        unsafe { RSlice::from_raw_parts(self.field_count, self.field_count_len as usize) }
53    }
54
55    /// Expands this into a TLEnum,with all the properties of an enum definition.
56    pub fn expand(self, other: GenericTLEnum, shared_vars: &'static SharedVars) -> TLEnum {
57        TLEnum {
58            field_count: self.field_count(),
59            variant_names: (&shared_vars.strings()[self.variant_names.to_range()]).into(),
60            fields: self.fields.expand(shared_vars),
61            exhaustiveness: other.exhaustiveness,
62            discriminants: other.discriminants,
63        }
64    }
65}
66
67///////////////////////////
68
69/// The layout of an enum,that might depend on generic parameters.
70#[repr(C)]
71#[derive(Debug, Copy, Clone, StableAbi)]
72#[sabi(unsafe_sabi_opaque_fields)]
73pub struct GenericTLEnum {
74    /// The exhaustiveness of this enum.
75    exhaustiveness: IsExhaustive,
76    /// The discriminants of the variants in the enum.
77    discriminants: TLDiscriminants,
78}
79
80impl GenericTLEnum {
81    /// Constructs a `GenericTLEnum`.
82    pub const fn new(exhaustiveness: IsExhaustive, discriminants: TLDiscriminants) -> Self {
83        Self {
84            exhaustiveness,
85            discriminants,
86        }
87    }
88
89    /// Constructs a `GenericTLEnum` for an exhaustive enum.
90    pub const fn exhaustive(discriminants: TLDiscriminants) -> Self {
91        Self::new(IsExhaustive::exhaustive(), discriminants)
92    }
93}
94
95///////////////////////////
96
97/// Every property about an enum specifically.
98#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99pub struct TLEnum {
100    /// The amount of fields of each variant.
101    pub field_count: RSlice<'static, u8>,
102
103    /// A ';' separated list of all variant names
104    pub variant_names: RStr<'static>,
105
106    /// All the fields of the enums,not separated by variant.
107    pub fields: TLFields,
108
109    /// The exhaustiveness of this enum.
110    pub exhaustiveness: IsExhaustive,
111
112    /// The discriminants of the variants in the enum.
113    pub discriminants: TLDiscriminants,
114}
115
116impl TLEnum {
117    /// Returns the amount of variants in the enum.
118    pub const fn variant_count(&self) -> usize {
119        self.field_count.len()
120    }
121    /// Returns an iterator over the names of the variants in this enum.
122    pub fn variant_names_iter(
123        &self,
124    ) -> impl ExactSizeIterator<Item = &'static str> + Clone + Debug + 'static {
125        GetVariantNames {
126            split: self.variant_names.as_str().split(';'),
127            length: self.field_count.len(),
128            current: 0,
129        }
130    }
131
132    /// Returns `self` and `other` sorted in a `(maximum,minimum)` pair,
133    /// based on the amount of variants.
134    pub const fn max_min<'a>(&'a self, other: &'a TLEnum) -> (&'a TLEnum, &'a TLEnum) {
135        if self.variant_count() < other.variant_count() {
136            (self, other)
137        } else {
138            (other, self)
139        }
140    }
141}
142
143impl Display for TLEnum {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        writeln!(f, "variants:{:?}", self.variant_names)?;
146        writeln!(
147            f,
148            "fields(all variants combined):\n{}",
149            self.fields.to_string().left_padder(4)
150        )?;
151        writeln!(f, "field counts(per-variant):{:?}", self.field_count)?;
152        writeln!(f, "exhaustiveness:{:?}", self.exhaustiveness)?;
153        writeln!(f, "discriminants:{:?}", self.discriminants)?;
154        Ok(())
155    }
156}
157
158///////////////////////////
159
160macro_rules! declare_tl_discriminants {
161    (
162        $((
163            $(#[$variant_attr:meta])*
164            $variant:ident ( $ty:ty ),
165            $single:ident,
166            $(#[$method_attr:meta])*
167            $method:ident
168        ))*
169    ) => (
170        /// The discriminants of an enum.
171        #[repr(C)]
172        #[derive(Copy, Clone, StableAbi)]
173        pub struct TLDiscriminants{
174            inner:TLDiscrsInner,
175        }
176
177        unsafe impl Sync for TLDiscriminants {}
178        unsafe impl Send for TLDiscriminants {}
179
180        #[repr(u8)]
181        #[derive(Copy, Clone, StableAbi)]
182        enum TLDiscrsInner{
183            $(
184                $(#[$variant_attr])*
185                // Storing the length and pointer like this so that the enum
186                // is only 2 usize large.
187                $variant{
188                    len:u16,
189                    discriminants:*const $ty,
190                },
191            )*
192        }
193
194        impl Debug for TLDiscriminants{
195            fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{
196                match self.inner {
197                    $(
198                        TLDiscrsInner::$variant{discriminants,len}=>unsafe{
199                            let slice=std::slice::from_raw_parts(discriminants,len as usize);
200                            Debug::fmt(slice,f)
201                        }
202                    )*
203                }
204            }
205        }
206
207        impl PartialEq for TLDiscriminants {
208            fn eq(&self,other:&Self)->bool{
209                match (self.inner,other.inner) {
210                    $(
211                        (
212                            TLDiscrsInner::$variant{discriminants: t_discr_ptr, len:t_len },
213                            TLDiscrsInner::$variant{discriminants: o_discr_ptr, len:o_len }
214                        )=>{
215                            let t_discrs=unsafe{
216                                RSlice::from_raw_parts(t_discr_ptr,t_len as usize)
217                            };
218                            let o_discrs=unsafe{
219                                RSlice::from_raw_parts(o_discr_ptr,o_len as usize)
220                            };
221                            t_discrs==o_discrs
222                        }
223                    )*
224                    _=>false,
225                }
226            }
227        }
228
229        impl Eq for TLDiscriminants{}
230
231        impl TLDiscriminants{
232
233            $(
234                $(#[$method_attr])*
235                pub const fn $method(arr:RSlice<'static,$ty>)->Self{
236                    let inner=TLDiscrsInner::$variant{
237                        len:arr.len() as u16,
238                        discriminants:arr.as_ptr(),
239                    };
240                    TLDiscriminants{inner}
241                }
242            )*
243
244            /// Gets the type of the discriminant in this `TLDiscriminants`.
245            pub const fn discriminant_repr(&self)->DiscriminantRepr{
246                match self.inner {
247                    $(
248                        TLDiscrsInner::$variant{..}=>DiscriminantRepr::$variant,
249                    )*
250                }
251            }
252
253            /// Compares this `TLDiscriminants` with another,
254            ///
255            /// # Errors
256            ///
257            /// This returns errors if:
258            ///
259            /// - The discriminant is of a different type
260            ///
261            /// - The value of the discriminants are different.
262            ///
263            pub fn compare(&self,other:&Self)->Result<(),RVec<AbiInstability>>{
264                let mut errs=RVec::new();
265                match (self.inner,other.inner) {
266                    $(
267                        (
268                            TLDiscrsInner::$variant{discriminants: t_discr_ptr, len:t_len },
269                            TLDiscrsInner::$variant{discriminants: o_discr_ptr, len:o_len }
270                        )=>{
271                            let t_discrs=unsafe{
272                                RSlice::from_raw_parts(t_discr_ptr,t_len as usize)
273                            };
274                            let o_discrs=unsafe{
275                                RSlice::from_raw_parts(o_discr_ptr,o_len as usize)
276                            };
277
278                            for (&t_discr,&o_discr) in
279                                t_discrs.as_slice().iter().zip(o_discrs.as_slice())
280                            {
281                                if t_discr!=o_discr {
282                                    push_err(
283                                        &mut errs,
284                                        t_discr,
285                                        o_discr,
286                                        |x| TLDiscriminant::$single(x as _),
287                                        AbiInstability::EnumDiscriminant,
288                                    );
289                                }
290                            }
291                        }
292                    )*
293                    _=>{
294                        push_err(
295                            &mut errs,
296                            self,
297                            other,
298                            |x| ReprAttr::Int(x.discriminant_repr()),
299                            AbiInstability::ReprAttr
300                        );
301                    }
302                }
303                if errs.is_empty(){
304                    Ok(())
305                }else{
306                    Err(errs)
307                }
308            }
309        }
310    )
311}
312
313declare_tl_discriminants! {
314    (
315        U8(u8) ,
316        Signed  ,
317        /// Constructs the variant from an `RSlice<'static,u8>`.
318        from_u8_slice
319    )
320    (
321        I8(i8) ,
322        Unsigned,
323        /// Constructs the variant from an `RSlice<'static,i8>`.
324        from_i8_slice
325    )
326    (
327        U16(u16) ,
328        Signed  ,
329        /// Constructs the variant from an `RSlice<'static,u16>`.
330        from_u16_slice
331    )
332    (
333        I16(i16) ,
334        Unsigned,
335        /// Constructs the variant from an `RSlice<'static,i16>`.
336        from_i16_slice
337    )
338    (
339        U32(u32) ,
340        Signed  ,
341        /// Constructs the variant from an `RSlice<'static,u32>`.
342        from_u32_slice
343    )
344    (
345        I32(i32) ,
346        Unsigned,
347        /// Constructs the variant from an `RSlice<'static,i32>`.
348        from_i32_slice
349    )
350    (
351        U64(u64) ,
352        Signed  ,
353        /// Constructs the variant from an `RSlice<'static,u64>`.
354        from_u64_slice
355    )
356    (
357        I64(i64) ,
358        Unsigned,
359        /// Constructs the variant from an `RSlice<'static,i64>`.
360        from_i64_slice
361    )
362    (
363        Usize(usize) ,
364        Usize,
365        /// Constructs the variant from an `RSlice<'static,usize>`.
366        from_usize_slice
367    )
368    (
369        Isize(isize) ,
370        Isize,
371        /// Constructs the variant from an `RSlice<'static,isize>`.
372        from_isize_slice
373    )
374}
375
376/// A discriminant of an enum variant.
377#[repr(u8)]
378#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
379#[sabi(unsafe_sabi_opaque_fields)]
380pub enum TLDiscriminant {
381    /// The assigned value of a discriminant in a `#[repr(isize)]` enum.
382    Isize(isize),
383    /// The assigned value of a discriminant in a `#[repr(usize)]` enum.
384    Usize(usize),
385    /// The assigned value of a discriminant in a `#[repr(i8/i16/i32/i64)]` enum.
386    Signed(i64),
387    /// The assigned value of a discriminant in a `#[repr(u8/u16/u32/u64)]` enum.
388    Unsigned(u64),
389}
390
391/// How the discriminant of an enum is represented.
392#[repr(u8)]
393#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
394#[sabi(unsafe_sabi_opaque_fields)]
395pub enum DiscriminantRepr {
396    /// The type of the discriminant for a `#[repr(u8)]`enum
397    U8,
398    /// The type of the discriminant for a `#[repr(i8)]`enum
399    I8,
400    /// The type of the discriminant for a `#[repr(u16)]`enum
401    U16,
402    /// The type of the discriminant for a `#[repr(i16)]`enum
403    I16,
404    /// The type of the discriminant for a `#[repr(u32)]`enum
405    U32,
406    /// The type of the discriminant for a `#[repr(i32)]`enum
407    I32,
408    /// The type of the discriminant for a `#[repr(u64)]`enum
409    U64,
410    /// The type of the discriminant for a `#[repr(i64)]`enum
411    I64,
412    /// Reserved,just in case that u128 gets a c-compatible layout
413    U128,
414    /// Reserved,just in case that i128 gets a c-compatible layout
415    I128,
416    /// The type of the discriminant for a `#[repr(usize)]`enum
417    Usize,
418    /// The type of the discriminant for a `#[repr(isize)]`enum
419    ///
420    /// This is the default discriminant type for `repr(C)`.
421    Isize,
422}
423
424/// Whether this enum is exhaustive,if it is,it can add variants in minor versions.
425#[repr(transparent)]
426#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
427#[sabi(unsafe_sabi_opaque_fields)]
428pub struct IsExhaustive {
429    value: Option<&'static TLNonExhaustive>,
430}
431
432impl IsExhaustive {
433    /// Constructs this `IsExhaustive` as being exhaustive.
434    pub const fn exhaustive() -> IsExhaustive {
435        IsExhaustive { value: None }
436    }
437    /// Constructs this `IsExhaustive` as being nonexhaustive.
438    pub const fn nonexhaustive(nonexhaustive: &'static TLNonExhaustive) -> IsExhaustive {
439        IsExhaustive {
440            value: Some(nonexhaustive),
441        }
442    }
443    /// Whether this is an exhaustive enum.
444    pub const fn is_exhaustive(&self) -> bool {
445        self.value.is_none()
446    }
447    /// Whether this is an nonexhaustive enum.
448    pub const fn is_nonexhaustive(&self) -> bool {
449        self.value.is_some()
450    }
451    /// Converts this to a TLNonExhaustive.Returning None if it is exhaustive.
452    pub const fn as_nonexhaustive(&self) -> Option<&'static TLNonExhaustive> {
453        self.value
454    }
455}
456
457/// Properties exclusive to nonexhaustive enums.
458#[repr(C)]
459#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
460#[sabi(unsafe_sabi_opaque_fields)]
461pub struct TLNonExhaustive {
462    original_size: usize,
463    original_alignment_pow2: u8,
464}
465
466impl TLNonExhaustive {
467    /// Constructs a `TLNonExhaustive` from the size and alignment of `T`
468    pub const fn new<T>() -> Self {
469        Self {
470            original_size: std::mem::size_of::<T>(),
471            original_alignment_pow2: log2_usize(mem::align_of::<T>()),
472        }
473    }
474
475    #[inline]
476    const fn original_size(&self) -> usize {
477        self.original_size
478    }
479    #[inline]
480    const fn original_alignment(&self) -> usize {
481        1_usize << (self.original_alignment_pow2 as u32)
482    }
483
484    /// Checks that `layout` is compatible with `self.size` and `self.alignment`,
485    /// returning an error if it's not.
486    pub fn check_compatible(
487        &self,
488        layout: &TypeLayout,
489    ) -> Result<(), IncompatibleWithNonExhaustive> {
490        let err =
491            layout.size() < self.original_size() || layout.alignment() < self.original_alignment();
492
493        if err {
494            Err(IncompatibleWithNonExhaustive {
495                full_type: layout.full_type().to_string().into(),
496                module_path: layout.mod_path(),
497                type_size: self.original_size(),
498                type_alignment: self.original_alignment(),
499                storage_size: layout.size(),
500                storage_alignment: layout.alignment(),
501            })
502        } else {
503            Ok(())
504        }
505    }
506}
507
508#[doc(hidden)]
509pub struct MakeTLNonExhaustive<T>(T);
510
511impl<T> MakeTLNonExhaustive<T> {
512    pub const NEW: TLNonExhaustive = TLNonExhaustive::new::<T>();
513}
514
515////////////////////////////
516
517/// An error declaring that the Storage of a nonexhaustive enum is
518/// not compatible with the enum.
519#[repr(C)]
520#[derive(Debug, Clone, PartialEq, Eq, StableAbi)]
521#[sabi(unsafe_sabi_opaque_fields)]
522pub struct IncompatibleWithNonExhaustive {
523    full_type: RString,
524    module_path: ModPath,
525    type_size: usize,
526    type_alignment: usize,
527    storage_size: usize,
528    storage_alignment: usize,
529}
530
531impl Display for IncompatibleWithNonExhaustive {
532    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533        write!(
534            f,
535            "Type '{ty}' has an incompatible layout for the storage.\n\
536             Type    size:{t_size} alignment:{t_align}
537             Storage size:{s_size} alignment:{s_align}
538             module_path:{mod_}
539            ",
540            ty = self.full_type,
541            t_size = self.type_size,
542            t_align = self.type_alignment,
543            s_size = self.storage_size,
544            s_align = self.storage_alignment,
545            mod_ = self.module_path,
546        )
547    }
548}
549
550impl std::error::Error for IncompatibleWithNonExhaustive {}
551
552/////////////////////////////////////////////////////////////////////////////
553
554/// An iterator that yields the names of an enum's variants.
555#[derive(Debug, Clone)]
556struct GetVariantNames {
557    split: std::str::Split<'static, char>,
558    length: usize,
559    current: usize,
560}
561
562impl Iterator for GetVariantNames {
563    type Item = &'static str;
564    fn next(&mut self) -> Option<Self::Item> {
565        if self.length == self.current {
566            return None;
567        }
568        let current = self.current;
569        self.current += 1;
570        match self.split.next().filter(|&x| !x.is_empty() || x == "_") {
571            Some(x) => Some(x),
572            None => Some(VARIANT_INDEX[current]),
573        }
574    }
575
576    fn size_hint(&self) -> (usize, Option<usize>) {
577        let len = self.length - self.current;
578        (len, Some(len))
579    }
580    fn count(self) -> usize {
581        self.length - self.current
582    }
583}
584
585impl std::iter::ExactSizeIterator for GetVariantNames {}
586
587static VARIANT_INDEX: [&str; 68] = [
588    "Variant0",
589    "Variant1",
590    "Variant2",
591    "Variant3",
592    "Variant4",
593    "Variant5",
594    "Variant6",
595    "Variant7",
596    "Variant8",
597    "Variant9",
598    "Variant10",
599    "Variant11",
600    "Variant12",
601    "Variant13",
602    "Variant14",
603    "Variant15",
604    "Variant16",
605    "Variant17",
606    "Variant18",
607    "Variant19",
608    "Variant20",
609    "Variant21",
610    "Variant22",
611    "Variant23",
612    "Variant24",
613    "Variant25",
614    "Variant26",
615    "Variant27",
616    "Variant28",
617    "Variant29",
618    "Variant30",
619    "Variant31",
620    "Variant32",
621    "Variant33",
622    "Variant34",
623    "Variant35",
624    "Variant36",
625    "Variant37",
626    "Variant38",
627    "Variant39",
628    "Variant40",
629    "Variant41",
630    "Variant42",
631    "Variant43",
632    "Variant44",
633    "Variant45",
634    "Variant46",
635    "Variant47",
636    "Variant48",
637    "Variant49",
638    "Variant50",
639    "Variant51",
640    "Variant52",
641    "Variant53",
642    "Variant54",
643    "Variant55",
644    "Variant56",
645    "Variant57",
646    "Variant58",
647    "Variant59",
648    "Variant60",
649    "Variant61",
650    "Variant62",
651    "Variant63",
652    "Variant64",
653    "Variant65",
654    "Variant66",
655    "Variant67",
656];