abi_stable/
nonexhaustive_enum.rs

1//! Contains types and traits for nonexhaustive enums.
2//!
3//! The most important type here is [NonExhaustive](./nonexhaustive/struct.NonExhaustive.html),
4//! which allows passing an enum which used the
5//! `#[derive(StableAbi)] #[sabi(kind(WithNonExhaustive(...)))]`
6//! attributes through ffi.
7//!
8
9#[doc(hidden)]
10pub mod doc_enums;
11
12#[cfg(any(feature = "testing", feature = "nonexhaustive_examples"))]
13pub mod examples;
14
15pub(crate) mod alt_c_functions;
16pub(crate) mod nonexhaustive;
17pub(crate) mod traits;
18pub(crate) mod vtable;
19
20pub use self::{
21    nonexhaustive::{
22        NonExhaustive, NonExhaustiveFor, NonExhaustiveSharedOps, NonExhaustiveWI, NonExhaustiveWS,
23        UnwrapEnumError,
24    },
25    traits::{
26        DeserializeEnum, EnumInfo, GetEnumInfo, NonExhaustiveMarker, SerializeEnum,
27        ValidDiscriminant,
28    },
29    vtable::GetVTable,
30};
31
32pub(crate) use self::traits::GetSerializeEnumProxy;
33
34/////////////////////////////////////////////////////////////
35
36/// Asserts that the size and alignment of an enum are valid for its default storage.
37#[track_caller]
38pub fn assert_correct_default_storage<E>()
39where
40    E: GetEnumInfo,
41{
42    assert_correct_storage::<E, E::DefaultStorage>(AssertCsArgs {
43        enum_ty: std::any::type_name::<E>(),
44        storage_ty: std::any::type_name::<E::DefaultStorage>(),
45    })
46}
47
48/// Arguments for [`assert_correct_storage`]
49pub struct AssertCsArgs {
50    /// The stringified type name of the enum.
51    pub enum_ty: &'static str,
52    /// The stringified type name of the storage.
53    pub storage_ty: &'static str,
54}
55
56impl AssertCsArgs {
57    /// Constant where both types are unknown.
58    pub const UNKNOWN: Self = Self {
59        enum_ty: "<unknown>",
60        storage_ty: "<unknown>",
61    };
62}
63
64/// Asserts that the size and alignment of an enum aree valid for this storage.
65///
66/// To make this function a `const fn`,
67/// the names of the `Enum` and `Storage` types must be passed separately.
68#[track_caller]
69pub const fn assert_correct_storage<Enum, Storage>(args: AssertCsArgs) {
70    #[derive(Debug)]
71    #[allow(dead_code)]
72    struct TypeAndStorageLayout {
73        enum_: &'static str,
74        enum_size: usize,
75        enum_alignment: usize,
76        storage_: &'static str,
77        storage_size: usize,
78        storage_alignment: usize,
79    }
80
81    #[track_caller]
82    const fn inner(lay: TypeAndStorageLayout) {
83        let msg = match (
84            lay.enum_alignment <= lay.storage_alignment,
85            lay.enum_size <= lay.storage_size,
86        ) {
87            (false, false) => {
88                "The alignment and size of the storage is smaller than the contained type"
89            }
90            (false, true) => "The alignment of the storage is lower than the contained type",
91            (true, false) => "The size of the storage is smaller than the contained type",
92            (true, true) => return,
93        };
94
95        const_panic::concat_panic!(
96            "\n",
97            display: msg,
98            ":\n",
99            "\tenum_: ",
100            lay.enum_,
101            "\n",
102            "\tenum_size: ",
103            lay.enum_size,
104            "\n",
105            "\tenum_alignment: ",
106            lay.enum_alignment,
107            "\n",
108            "\tstorage_: ",
109            lay.storage_,
110            "\n",
111            "\tstorage_size: ",
112            lay.storage_size,
113            "\n",
114            "\tstorage_alignment: ",
115            lay.storage_alignment,
116            "\n",
117        )
118    }
119
120    inner(TypeAndStorageLayout {
121        enum_: args.enum_ty,
122        enum_size: std::mem::size_of::<Enum>(),
123        enum_alignment: std::mem::align_of::<Enum>(),
124        storage_: args.storage_ty,
125        storage_size: std::mem::size_of::<Storage>(),
126        storage_alignment: std::mem::align_of::<Storage>(),
127    })
128}