Skip to main content

rust_spec/core_impls/
wrappers.rs

1#[cfg(feature = "alloc")]
2use alloc::{string::String, vec::Vec};
3use core::{
4    cmp::Reverse,
5    convert::Infallible,
6    marker::{PhantomData, PhantomPinned},
7    mem::{ManuallyDrop, MaybeUninit},
8    num::{NonZero, Saturating, Wrapping},
9};
10
11#[cfg(feature = "alloc")]
12use crate::drop::{AutoDrop, CustomDrop};
13use crate::{
14    NonOpaque, RustSpec, Stable, Unstable,
15    drop::{NeedsDrop, NoDrop},
16    layout::{NonRobust, Robust},
17    mutability::{Exclusive, WithInterior, WithoutInterior},
18    niche::{WithNiche, WithoutNiche},
19    size,
20};
21
22macro_rules! non_zero_derive {
23    ($($primitive:ty),+ $(,)?) => {$(
24        unsafe impl RustSpec for NonZero<$primitive> {
25            type Layout = Stable;
26            type Size = size::Sized<crate::Gt<crate::Zero>>;
27            type __Alignment = <$primitive as RustSpec>::__Alignment;
28            type Trap = NonRobust;
29            type Niche = WithNiche<Stable>;
30            type Drop = NoDrop;
31            type Mutability = Exclusive<WithoutInterior>;
32            type Opacity = NonOpaque;
33            type __IndirectTrap = Robust;
34        }
35    )+};
36}
37
38macro_rules! stable_robust_zst {
39    (($($generics:tt)*) => $ty:ty) => {
40        unsafe impl<$($generics)*> RustSpec for $ty {
41            type Layout = Stable;
42            type Size = size::Sized<size::Zero>;
43            type __Alignment = crate::One;
44            type Trap = Robust;
45            type Niche = WithoutNiche;
46            type Drop = NoDrop;
47            type Mutability = Exclusive<WithoutInterior>;
48            type Opacity = NonOpaque;
49            type __IndirectTrap = Robust;
50        }
51    };
52}
53
54macro_rules! transparent_wrapper {
55    (($($generics:tt)*) => $ty:ty) => {
56        unsafe impl<$($generics)*> RustSpec for $ty
57        where
58            T::Drop: crate::drop::DropKind,
59        {
60            type Layout = T::Layout;
61            type Size = T::Size;
62            type __Alignment = T::__Alignment;
63            type Trap = T::Trap;
64            type Niche = T::Niche;
65            type Drop = NeedsDrop<T::Drop>;
66            type Mutability = T::Mutability;
67            type Opacity = NonOpaque;
68            type __IndirectTrap = T::__IndirectTrap;
69        }
70    };
71}
72
73non_zero_derive!(
74    u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize
75);
76
77stable_robust_zst!(() => ());
78stable_robust_zst!(() => Infallible);
79stable_robust_zst!(() => PhantomPinned);
80stable_robust_zst!((T: ?Sized) => PhantomData<T>);
81
82transparent_wrapper!((T: RustSpec) => Reverse<T>);
83transparent_wrapper!((T: RustSpec) => Wrapping<T>);
84transparent_wrapper!((T: RustSpec) => Saturating<T>);
85
86unsafe impl<T: RustSpec + ?Sized> RustSpec for ManuallyDrop<T> {
87    type Layout = T::Layout;
88    type Size = T::Size;
89    type __Alignment = T::__Alignment;
90    type Trap = T::Trap;
91    type Niche = T::Niche;
92    type Drop = NoDrop;
93    type Mutability = T::Mutability;
94    type Opacity = NonOpaque;
95    type __IndirectTrap = T::__IndirectTrap;
96}
97
98// Keep the projection helper inaccessible outside this implementation block.
99const _: () = {
100    pub trait UninitMutability {
101        type Output;
102    }
103
104    impl UninitMutability for Exclusive<WithoutInterior> {
105        type Output = Self;
106    }
107    impl<R> UninitMutability for WithInterior<R> {
108        type Output = WithInterior<Robust>;
109    }
110    impl<R> UninitMutability for Exclusive<WithInterior<R>> {
111        type Output = Exclusive<WithInterior<Robust>>;
112    }
113
114    unsafe impl<T: RustSpec<Mutability: UninitMutability>> RustSpec for MaybeUninit<T> {
115        type Layout = T::Layout;
116        type Size = T::Size;
117        type __Alignment = T::__Alignment;
118        type Trap = Robust;
119        type Niche = WithoutNiche;
120        type Drop = NoDrop;
121        // Preserve shared mutability, but impose no validity requirements on
122        // uninitialized contents or anything reachable through those contents.
123        type Mutability = <T::Mutability as UninitMutability>::Output;
124        type Opacity = NonOpaque;
125        type __IndirectTrap = Robust;
126    }
127};
128
129unsafe impl RustSpec for str {
130    type Layout = Stable;
131    type Size = size::MetaSized<size::SliceLike>;
132    type __Alignment = crate::One;
133    type Trap = NonRobust;
134    // TODO: This should not be set at all
135    type Niche = WithNiche<Unstable>;
136    type Drop = NoDrop;
137    type Mutability = Exclusive<WithoutInterior>;
138    type Opacity = NonOpaque;
139    type __IndirectTrap = Robust;
140}
141#[cfg(feature = "alloc")]
142unsafe impl RustSpec for String {
143    type Layout = Unstable;
144    type Size = size::Sized<crate::Gt<crate::Zero>>;
145    type __Alignment = <usize as RustSpec>::__Alignment;
146    type Trap = NonRobust;
147    type Niche = WithNiche<Unstable>;
148    type Drop = AutoDrop;
149    type Mutability = Exclusive<WithoutInterior>;
150    type Opacity = NonOpaque;
151    type __IndirectTrap = NonRobust;
152}
153
154#[cfg(feature = "alloc")]
155unsafe impl<T: RustSpec<Mutability: crate::mutability::PointerMutability>> RustSpec for Vec<T> {
156    type Layout = Unstable;
157    type Size = size::Sized<crate::Gt<crate::Zero>>;
158    type __Alignment = <usize as RustSpec>::__Alignment;
159    type Trap = NonRobust;
160    type Niche = WithNiche<Unstable>;
161    type Drop = CustomDrop<AutoDrop>;
162    type Mutability = <T::Mutability as crate::mutability::PointerMutability>::Output;
163    type Opacity = NonOpaque;
164    type __IndirectTrap = T::Trap;
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170    use core::cell::{Cell, UnsafeCell};
171    use static_assertions::assert_impl_all;
172
173    #[test]
174    fn maybe_uninit_preserves_mutability_without_inner_traps() {
175        assert_impl_all!(MaybeUninit<bool>:
176            RustSpec<Mutability = Exclusive<WithoutInterior>, Trap = Robust>);
177        assert_impl_all!(MaybeUninit<UnsafeCell<bool>>:
178            RustSpec<Mutability = WithInterior<Robust>, Trap = Robust>);
179        assert_impl_all!(MaybeUninit<Cell<bool>>:
180            RustSpec<Mutability = WithInterior<Robust>, Trap = Robust>);
181        assert_impl_all!(MaybeUninit<&'static UnsafeCell<bool>>:
182            RustSpec<Mutability = Exclusive<WithInterior<Robust>>, Trap = Robust>);
183        assert_impl_all!([MaybeUninit<UnsafeCell<bool>>; 2]:
184            RustSpec<Mutability = WithInterior<Robust>>);
185        assert_impl_all!(UnsafeCell<MaybeUninit<bool>>:
186            RustSpec<Mutability = WithInterior<Robust>>);
187        assert_impl_all!(MaybeUninit<MaybeUninit<UnsafeCell<bool>>>:
188            RustSpec<Mutability = WithInterior<Robust>>);
189        assert_impl_all!(ManuallyDrop<UnsafeCell<bool>>:
190            RustSpec<Mutability = WithInterior<NonRobust>, Trap = NonRobust>);
191
192        #[cfg(feature = "alloc")]
193        {
194            use alloc::boxed::Box;
195            assert_impl_all!(Box<MaybeUninit<UnsafeCell<bool>>>:
196                RustSpec<Mutability = Exclusive<WithInterior<Robust>>>);
197            assert_impl_all!(MaybeUninit<Box<UnsafeCell<bool>>>:
198                RustSpec<Mutability = Exclusive<WithInterior<Robust>>, Trap = Robust>);
199        }
200    }
201}