Skip to main content

rust_spec/
niche.rs

1//! Logic related to the conversion of [`Option<T>`] to and from FFI-compatible representation
2
3use core::{convert::Infallible, ops::Add};
4
5use crate::{
6    Stable, Unstable,
7    layout::{LayoutKind, NonRobust, Robust},
8};
9
10/// Marker for a type with no classified niche value.
11pub enum WithoutNiche {}
12
13/// Marker for a type that has a niche value.
14// TODO: Removed the bound `: Layout` because the API will be modified
15pub struct WithNiche<K>(core::marker::PhantomData<K>, Infallible);
16
17/// Representation contributions when adding an empty alternative to a payload.
18///
19/// Add `Layout` to the payload layout and `Trap` to its indirect trap
20/// classification. `Niche` describes the resulting nullable representation.
21#[sealed::sealed]
22pub trait NullableRepresentation {
23    type Layout: LayoutKind;
24    type Trap;
25    type Niche;
26}
27
28#[sealed::sealed]
29impl NullableRepresentation for WithoutNiche {
30    type Layout = Unstable;
31    type Trap = NonRobust;
32    type Niche = WithNiche<Unstable>;
33}
34
35#[sealed::sealed]
36impl NullableRepresentation for WithNiche<Unstable> {
37    // Without a count of available niches, consuming one cannot establish
38    // robustness or whether any guaranteed niche remains.
39    type Layout = Unstable;
40    type Trap = NonRobust;
41    type Niche = WithNiche<Unstable>;
42}
43
44#[sealed::sealed]
45impl NullableRepresentation for WithNiche<Stable> {
46    type Layout = Stable;
47    type Trap = Robust;
48    type Niche = WithoutNiche;
49}
50
51impl Add for WithoutNiche {
52    type Output = Self;
53
54    fn add(self, _: Self) -> Self::Output {
55        unreachable!()
56    }
57}
58impl<K: LayoutKind> Add<WithNiche<K>> for WithoutNiche {
59    type Output = WithNiche<Unstable>;
60
61    fn add(self, _: WithNiche<K>) -> Self::Output {
62        unreachable!()
63    }
64}
65impl<K: LayoutKind> Add<WithoutNiche> for WithNiche<K> {
66    type Output = WithNiche<Unstable>;
67
68    fn add(self, _: WithoutNiche) -> Self::Output {
69        unreachable!()
70    }
71}
72impl<K: LayoutKind, U: LayoutKind> Add<WithNiche<U>> for WithNiche<K> {
73    type Output = WithNiche<Unstable>;
74
75    fn add(self, _: WithNiche<U>) -> Self::Output {
76        unreachable!()
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use core::num::NonZero as StdNonZero;
83
84    use static_assertions::assert_impl_all;
85
86    use super::*;
87    use crate::{
88        RustSpec,
89        mutability::{Exclusive, WithoutInterior},
90    };
91
92    #[test]
93    fn nested_option_niche_family() {
94        assert_impl_all!(Option<bool>:
95            RustSpec<
96                Layout = Unstable,
97                Size = crate::size::Sized<crate::Gt<crate::Zero>>,
98                __Alignment = crate::One,
99                Trap = NonRobust,
100                Niche = WithNiche<crate::Unstable>,
101                Mutability = Exclusive<WithoutInterior>,
102                __IndirectTrap = Robust,
103            >,
104        );
105
106        assert_impl_all!(Option<Option<bool>>:
107            RustSpec<
108                Layout = Unstable,
109                Size = crate::size::Sized<crate::Gt<crate::Zero>>,
110                __Alignment = crate::One,
111                Trap = NonRobust,
112                Niche = WithNiche<crate::Unstable>,
113                Mutability = Exclusive<WithoutInterior>,
114                __IndirectTrap = Robust,
115            >,
116        );
117
118        assert_impl_all!(Option<(u8, StdNonZero<u8>)>:
119            RustSpec<
120                Layout = Unstable,
121                Size = crate::size::Sized<crate::Gt<crate::Zero>>,
122                __Alignment = crate::One,
123                Trap = NonRobust,
124                // FIXME: The type should be WithoutNiche
125                Niche = WithNiche<crate::Unstable>,
126                Mutability = Exclusive<WithoutInterior>,
127                __IndirectTrap = Robust,
128            >,
129        );
130    }
131}