1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use crate::Pod;
use core::num::{
    NonZeroU8,
    NonZeroI8,
    NonZeroU16,
    NonZeroI16,
    NonZeroU32,
    NonZeroI32,
    NonZeroU64,
    NonZeroI64,
    NonZeroU128,
    NonZeroI128,
    NonZeroUsize,
    NonZeroIsize,
};

/// Marker trait for "plain old data" types with no uninit (or padding) bytes.
///
/// The requirements for this is very similar to [`Pod`],
/// except that it doesn't require that all bit patterns of the type are valid, i.e.
/// it does not require the type to be [`Zeroable`][crate::Zeroable].
/// This limits what you can do with a type of this kind, but also broadens the
/// included types to things like C-style enums. Notably, you can only cast from
/// *immutable* references to a [`NoUninit`] type into *immutable* references of any other
/// type, no casting of mutable references or mutable references to slices etc.
///
/// [`Pod`] is a subset of [`NoUninit`], meaning that any `T: Pod` is also
/// [`NoUninit`] but any `T: NoUninit` is not necessarily [`Pod`]. If possible,
/// prefer implementing [`Pod`] directly. To get more [`Pod`]-like functionality for
/// a type that is only [`NoUninit`], consider also implementing [`CheckedBitPattern`][crate::CheckedBitPattern].
///
/// # Derive
///
/// A `#[derive(NoUninit)]` macro is provided under the `derive` feature flag which will
/// automatically validate the requirements of this trait and implement the
/// trait for you for both enums and structs. This is the recommended method for
/// implementing the trait, however it's also possible to do manually. If you
/// implement it manually, you *must* carefully follow the below safety rules.
///
/// # Safety
///
/// The same as [`Pod`] except we disregard the rule about it must
/// allow any bit pattern (i.e. it does not need to be [`Zeroable`][crate::Zeroable]).
/// Still, this is a quite strong guarantee about a type, so *be careful* whem
/// implementing it manually.
///
/// * The type must be inhabited (eg: no
///   [Infallible](core::convert::Infallible)).
/// * The type must not contain any uninit (or padding) bytes, either in the middle or on
///   the end (eg: no `#[repr(C)] struct Foo(u8, u16)`, which has padding in the
///   middle, and also no `#[repr(C)] struct Foo(u16, u8)`, which has padding on
///   the end).
/// * Structs need to have all fields also be `NoUninit`.
/// * Structs need to be `repr(C)` or `repr(transparent)`. In the case of
///   `repr(C)`, the `packed` and `align` repr modifiers can be used as long as
///   all other rules end up being followed.
/// * Enums need to have an explicit `#[repr(Int)]`
/// * Enums must have only fieldless variants
/// * It is disallowed for types to contain pointer types, `Cell`, `UnsafeCell`, atomics, and any
///   other forms of interior mutability.
/// * More precisely: A shared reference to the type must allow reads, and *only* reads. RustBelt's
///   separation logic is based on the notion that a type is allowed to define a sharing predicate,
///   its own invariant that must hold for shared references, and this predicate is the reasoning
///   that allow it to deal with atomic and cells etc. We require the sharing predicate to be
///   trivial and permit only read-only access.
/// * There's probably more, don't mess it up (I mean it).
pub unsafe trait NoUninit: Sized + Copy + 'static {}

unsafe impl<T: Pod> NoUninit for T {}

unsafe impl NoUninit for char {}

unsafe impl NoUninit for bool {}

unsafe impl NoUninit for NonZeroU8 {}
unsafe impl NoUninit for NonZeroI8 {}
unsafe impl NoUninit for NonZeroU16 {}
unsafe impl NoUninit for NonZeroI16 {}
unsafe impl NoUninit for NonZeroU32 {}
unsafe impl NoUninit for NonZeroI32 {}
unsafe impl NoUninit for NonZeroU64 {}
unsafe impl NoUninit for NonZeroI64 {}
unsafe impl NoUninit for NonZeroU128 {}
unsafe impl NoUninit for NonZeroI128 {}
unsafe impl NoUninit for NonZeroUsize {}
unsafe impl NoUninit for NonZeroIsize {}