Skip to main content

rust_spec/
mutability.rs

1//! Mutability classification of Rust types.
2use core::{convert::Infallible, marker::PhantomData, ops::Add};
3
4use crate::Sum;
5
6/// No reachable interior-mutable storage.
7pub enum WithoutInterior {}
8
9/// Closed family of reachable-interior classifications accepted by [`Exclusive`].
10#[sealed::sealed]
11pub trait ExclusiveKind {}
12
13#[sealed::sealed]
14impl ExclusiveKind for WithoutInterior {}
15
16#[sealed::sealed]
17impl<R> ExclusiveKind for WithInterior<R> {}
18
19/// Immediate storage requires exclusive access to mutate. `I` describes whether
20/// interior-mutable storage is reachable through indirection.
21pub struct Exclusive<I: ExclusiveKind>(PhantomData<I>, Infallible);
22
23/// Storage mutable through shared access. `R` aggregates the robustness of all
24/// interior-mutable parts, including those reachable through indirection,
25/// independently of the whole value's `RustSpec::Trap` classification.
26pub struct WithInterior<R>(PhantomData<R>, Infallible);
27
28/// Convert a pointee classification to the classification of its pointer.
29#[sealed::sealed]
30pub trait PointerMutability {
31    type Output;
32}
33
34#[sealed::sealed]
35impl<I: ExclusiveKind> PointerMutability for Exclusive<I> {
36    type Output = Self;
37}
38#[sealed::sealed]
39impl<R> PointerMutability for WithInterior<R> {
40    type Output = Exclusive<Self>;
41}
42
43impl Add<Self> for WithoutInterior {
44    type Output = Self;
45
46    fn add(self, _: Self) -> Self::Output {
47        unreachable!()
48    }
49}
50impl<R> Add<WithInterior<R>> for WithoutInterior {
51    type Output = WithInterior<R>;
52
53    fn add(self, _: WithInterior<R>) -> Self::Output {
54        unreachable!()
55    }
56}
57impl<R> Add<WithoutInterior> for WithInterior<R> {
58    type Output = Self;
59
60    fn add(self, _: WithoutInterior) -> Self::Output {
61        unreachable!()
62    }
63}
64impl<L: Add<R>, R> Add<WithInterior<R>> for WithInterior<L> {
65    type Output = WithInterior<L::Output>;
66
67    fn add(self, _: WithInterior<R>) -> Self::Output {
68        unreachable!()
69    }
70}
71impl<L: ExclusiveKind + Add<R, Output: ExclusiveKind>, R: ExclusiveKind> Add<Exclusive<R>>
72    for Exclusive<L>
73{
74    type Output = Exclusive<L::Output>;
75
76    fn add(self, _: Exclusive<R>) -> Self::Output {
77        unreachable!()
78    }
79}
80impl<I: ExclusiveKind + Add<WithInterior<R>>, R> Add<WithInterior<R>> for Exclusive<I> {
81    type Output = Sum<I, WithInterior<R>>;
82
83    fn add(self, _: WithInterior<R>) -> Self::Output {
84        unreachable!()
85    }
86}
87impl<I: ExclusiveKind, R> Add<Exclusive<I>> for WithInterior<R>
88where
89    Self: Add<I>,
90{
91    type Output = Sum<Self, I>;
92
93    fn add(self, _: Exclusive<I>) -> Self::Output {
94        unreachable!()
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    #[cfg(feature = "alloc")]
101    use alloc::{boxed::Box, vec::Vec};
102
103    use static_assertions::assert_impl_all;
104
105    use crate::{
106        RustSpec, Stable, Unstable,
107        layout::{NonRobust, Robust},
108        mutability::{Exclusive, WithInterior, WithoutInterior},
109        niche::{WithNiche, WithoutNiche},
110        size::Sized as RustSpecSized,
111    };
112
113    #[test]
114    fn exclusive_kind_accepts_only_reachability_markers() {
115        use super::{ExclusiveKind, WithoutInterior};
116        assert_impl_all!(WithoutInterior: ExclusiveKind);
117        assert_impl_all!(WithInterior<Robust>: ExclusiveKind);
118        assert_impl_all!(WithInterior<NonRobust>: ExclusiveKind);
119        static_assertions::assert_not_impl_any!(Exclusive<WithoutInterior>: ExclusiveKind);
120        static_assertions::assert_not_impl_any!(u8: ExclusiveKind);
121    }
122
123    #[test]
124    fn indirect_and_aggregate_mutability() {
125        use core::cell::UnsafeCell;
126        use core::ptr::NonNull;
127        assert_impl_all!(&&UnsafeCell<u8>: RustSpec<Mutability = Exclusive<WithInterior<Robust>>>);
128        assert_impl_all!(*const UnsafeCell<u8>: RustSpec<Mutability = Exclusive<WithInterior<Robust>>>);
129        assert_impl_all!(NonNull<UnsafeCell<u8>>: RustSpec<Mutability = Exclusive<WithInterior<Robust>>>);
130        assert_impl_all!((u8, &UnsafeCell<u8>): RustSpec<Mutability = Exclusive<WithInterior<Robust>>>);
131        assert_impl_all!((UnsafeCell<u8>, &UnsafeCell<u8>): RustSpec<Mutability = WithInterior<Robust>>);
132        #[cfg(feature = "alloc")]
133        assert_impl_all!(Box<Box<UnsafeCell<u8>>>: RustSpec<Mutability = Exclusive<WithInterior<Robust>>>);
134    }
135
136    #[test]
137    fn mixed_mutability_preserves_reachable_robustness() {
138        use core::cell::UnsafeCell;
139
140        type Mixed = (UnsafeCell<u8>, &'static UnsafeCell<bool>);
141        type Reversed = (&'static UnsafeCell<bool>, UnsafeCell<u8>);
142        assert_impl_all!(Mixed: RustSpec<Mutability = WithInterior<NonRobust>>);
143        assert_impl_all!(Reversed: RustSpec<Mutability = WithInterior<NonRobust>>);
144        assert_impl_all!(&&Mixed: RustSpec<Mutability = Exclusive<WithInterior<NonRobust>>>);
145        assert_impl_all!((u8, &Mixed): RustSpec<Mutability = Exclusive<WithInterior<NonRobust>>>);
146        assert_impl_all!((UnsafeCell<u8>, &Mixed): RustSpec<Mutability = WithInterior<NonRobust>>);
147        assert_impl_all!((&Mixed, UnsafeCell<u8>): RustSpec<Mutability = WithInterior<NonRobust>>);
148        assert_impl_all!((bool, UnsafeCell<u8>): RustSpec<Trap = NonRobust, Mutability = WithInterior<Robust>>);
149    }
150
151    #[test]
152    fn mutability_family_tracks_shared_mutability() {
153        use core::{
154            cell::{Cell, UnsafeCell},
155            ptr::NonNull,
156        };
157
158        assert_impl_all!(u8:
159            RustSpec<
160                Layout = Stable,
161                Size = RustSpecSized<crate::Gt<crate::Zero>>,
162                __Alignment = crate::One,
163                Trap = Robust,
164                Niche = WithoutNiche,
165                Mutability = Exclusive<WithoutInterior>,
166                __IndirectTrap = Robust,
167            >,
168        );
169        assert_impl_all!(UnsafeCell<u8>:
170            RustSpec<
171                Layout = Stable,
172                Size = RustSpecSized<crate::Gt<crate::Zero>>,
173                __Alignment = crate::One,
174                Trap = Robust,
175                Niche = WithoutNiche,
176                Mutability = WithInterior<Robust>,
177                __IndirectTrap = Robust,
178            >,
179        );
180        assert_impl_all!(Cell<u8>:
181            RustSpec<
182                Layout = Stable,
183                Size = RustSpecSized<crate::Gt<crate::Zero>>,
184                __Alignment = crate::One,
185                Trap = Robust,
186                Niche = WithoutNiche,
187                Mutability = WithInterior<Robust>,
188                __IndirectTrap = Robust,
189            >,
190        );
191        assert_impl_all!((UnsafeCell<u8>, UnsafeCell<u8>):
192            RustSpec<
193                Layout = Unstable,
194                Size = RustSpecSized<crate::Gt<crate::Zero>>,
195                __Alignment = crate::One,
196                Trap = Robust,
197                Niche = WithoutNiche,
198                Mutability = WithInterior<Robust>,
199                __IndirectTrap = Robust,
200            >,
201        );
202        assert_impl_all!((UnsafeCell<u8>, u8):
203            RustSpec<
204                Layout = Unstable,
205                Size = RustSpecSized<crate::Gt<crate::Zero>>,
206                __Alignment = crate::One,
207                Trap = Robust,
208                Niche = WithoutNiche,
209                Mutability = WithInterior<Robust>,
210                __IndirectTrap = Robust,
211            >,
212        );
213        assert_impl_all!([UnsafeCell<u8>; 2]:
214            RustSpec<
215                Layout = Stable,
216                Size = RustSpecSized<crate::Gt<crate::Zero>>,
217                __Alignment = crate::One,
218                Trap = Robust,
219                Niche = WithoutNiche,
220                Mutability = WithInterior<Robust>,
221                __IndirectTrap = Robust,
222            >,
223        );
224        assert_impl_all!([u8; 2]:
225            RustSpec<
226                Layout = Stable,
227                Size = RustSpecSized<crate::Gt<crate::Zero>>,
228                __Alignment = crate::One,
229                Trap = Robust,
230                Niche = WithoutNiche,
231                Mutability = Exclusive<WithoutInterior>,
232                __IndirectTrap = Robust,
233            >,
234        );
235        assert_impl_all!(&UnsafeCell<u8>:
236            RustSpec<
237                Layout = Stable,
238                Size = RustSpecSized<crate::Gt<crate::Zero>>,
239                __Alignment = <usize as RustSpec>::__Alignment,
240                Trap = NonRobust,
241                Niche = WithNiche<Stable>,
242                Mutability = Exclusive<WithInterior<Robust>>,
243                __IndirectTrap = Robust,
244            >,
245        );
246        assert_impl_all!(&mut UnsafeCell<u8>:
247            RustSpec<
248                Layout = Stable,
249                Size = RustSpecSized<crate::Gt<crate::Zero>>,
250                __Alignment = <usize as RustSpec>::__Alignment,
251                Trap = NonRobust,
252                Niche = WithNiche<Stable>,
253                Mutability = Exclusive<WithInterior<Robust>>,
254                __IndirectTrap = Robust,
255            >,
256        );
257        assert_impl_all!(*const UnsafeCell<u8>:
258            RustSpec<
259                Layout = Stable,
260                Size = RustSpecSized<crate::Gt<crate::Zero>>,
261                __Alignment = <usize as RustSpec>::__Alignment,
262                Trap = Robust,
263                Niche = WithoutNiche,
264                Mutability = Exclusive<WithInterior<Robust>>,
265                __IndirectTrap = Robust,
266            >,
267        );
268        assert_impl_all!(*mut UnsafeCell<u8>:
269            RustSpec<
270                Layout = Stable,
271                Size = RustSpecSized<crate::Gt<crate::Zero>>,
272                __Alignment = <usize as RustSpec>::__Alignment,
273                Trap = Robust,
274                Niche = WithoutNiche,
275                Mutability = Exclusive<WithInterior<Robust>>,
276                __IndirectTrap = Robust,
277            >,
278        );
279        assert_impl_all!(NonNull<UnsafeCell<u8>>:
280            RustSpec<
281                Layout = Stable,
282                Size = RustSpecSized<crate::Gt<crate::Zero>>,
283                __Alignment = <usize as RustSpec>::__Alignment,
284                Trap = NonRobust,
285                Niche = WithNiche<Stable>,
286                Mutability = Exclusive<WithInterior<Robust>>,
287                __IndirectTrap = Robust,
288            >,
289        );
290        assert_impl_all!(Option<UnsafeCell<u8>>:
291            RustSpec<
292                Layout = Unstable,
293                Size = RustSpecSized<crate::Gt<crate::Zero>>,
294                __Alignment = crate::One,
295                Trap = NonRobust,
296                Niche = WithNiche<Unstable>,
297                Mutability = WithInterior<Robust>,
298                __IndirectTrap = Robust,
299            >,
300        );
301
302        #[cfg(feature = "alloc")]
303        assert_impl_all!(Box<UnsafeCell<u8>>:
304            RustSpec<
305                Layout = Stable,
306                Size = RustSpecSized<crate::Gt<crate::Zero>>,
307                __Alignment = <usize as RustSpec>::__Alignment,
308                Trap = NonRobust,
309                Niche = WithNiche<Stable>,
310                Mutability = Exclusive<WithInterior<Robust>>,
311                __IndirectTrap = Robust,
312            >,
313        );
314        #[cfg(feature = "alloc")]
315        assert_impl_all!(Box<[UnsafeCell<u8>]>:
316            RustSpec<
317                Layout = Unstable,
318                Size = RustSpecSized<crate::Gt<crate::Zero>>,
319                __Alignment = <usize as RustSpec>::__Alignment,
320                Trap = NonRobust,
321                Niche = WithNiche<Unstable>,
322                Mutability = Exclusive<WithInterior<Robust>>,
323                __IndirectTrap = Robust,
324            >,
325        );
326        #[cfg(feature = "alloc")]
327        assert_impl_all!(Vec<UnsafeCell<u8>>:
328            RustSpec<
329                Layout = Unstable,
330                Size = RustSpecSized<crate::Gt<crate::Zero>>,
331                __Alignment = <usize as RustSpec>::__Alignment,
332                Trap = NonRobust,
333                Niche = WithNiche<Unstable>,
334                Mutability = Exclusive<WithInterior<Robust>>,
335                __IndirectTrap = Robust,
336            >,
337        );
338    }
339}