1 use super::*; 2 use core::mem::{size_of, transmute_copy}; 3 4 /// A trait indicating that: 5 /// 6 /// 1. A type has an equivalent representation to some known integral type. 7 /// 2. All instances of this type fall in a fixed range of values. 8 /// 3. Within that range, there are no gaps. 9 /// 10 /// This is generally useful for fieldless enums (aka "c-style" enums), however 11 /// it's important that it only be used for those with an explicit `#[repr]`, as 12 /// `#[repr(Rust)]` fieldess enums have an unspecified layout. 13 /// 14 /// Additionally, you shouldn't assume that all implementations are enums. Any 15 /// type which meets the requirements above while following the rules under 16 /// "Safety" below is valid. 17 /// 18 /// # Example 19 /// 20 /// ``` 21 /// # use bytemuck::Contiguous; 22 /// #[repr(u8)] 23 /// #[derive(Debug, Copy, Clone, PartialEq)] 24 /// enum Foo { 25 /// A = 0, 26 /// B = 1, 27 /// C = 2, 28 /// D = 3, 29 /// E = 4, 30 /// } 31 /// unsafe impl Contiguous for Foo { 32 /// type Int = u8; 33 /// const MIN_VALUE: u8 = Foo::A as u8; 34 /// const MAX_VALUE: u8 = Foo::E as u8; 35 /// } 36 /// assert_eq!(Foo::from_integer(3).unwrap(), Foo::D); 37 /// assert_eq!(Foo::from_integer(8), None); 38 /// assert_eq!(Foo::C.into_integer(), 2); 39 /// ``` 40 /// # Safety 41 /// 42 /// This is an unsafe trait, and incorrectly implementing it is undefined 43 /// behavior. 44 /// 45 /// Informally, by implementing it, you're asserting that `C` is identical to 46 /// the integral type `C::Int`, and that every `C` falls between `C::MIN_VALUE` 47 /// and `C::MAX_VALUE` exactly once, without any gaps. 48 /// 49 /// Precisely, the guarantees you must uphold when implementing `Contiguous` for 50 /// some type `C` are: 51 /// 52 /// 1. The size of `C` and `C::Int` must be the same, and neither may be a ZST. 53 /// (Note: alignment is explicitly allowed to differ) 54 /// 55 /// 2. `C::Int` must be a primitive integer, and not a wrapper type. In the 56 /// future, this may be lifted to include cases where the behavior is 57 /// identical for a relevant set of traits (Ord, arithmetic, ...). 58 /// 59 /// 3. All `C::Int`s which are in the *inclusive* range between `C::MIN_VALUE` 60 /// and `C::MAX_VALUE` are bitwise identical to unique valid instances of 61 /// `C`. 62 /// 63 /// 4. There exist no instances of `C` such that their bitpatterns, when 64 /// interpreted as instances of `C::Int`, fall outside of the `MAX_VALUE` / 65 /// `MIN_VALUE` range -- It is legal for unsafe code to assume that if it 66 /// gets a `C` that implements `Contiguous`, it is in the appropriate range. 67 /// 68 /// 5. Finally, you promise not to provide overridden implementations of 69 /// `Contiguous::from_integer` and `Contiguous::into_integer`. 70 /// 71 /// For clarity, the following rules could be derived from the above, but are 72 /// listed explicitly: 73 /// 74 /// - `C::MAX_VALUE` must be greater or equal to `C::MIN_VALUE` (therefore, `C` 75 /// must be an inhabited type). 76 /// 77 /// - There exist no two values between `MIN_VALUE` and `MAX_VALUE` such that 78 /// when interpreted as a `C` they are considered identical (by, say, match). 79 pub unsafe trait Contiguous: Copy + 'static { 80 /// The primitive integer type with an identical representation to this 81 /// type. 82 /// 83 /// Contiguous is broadly intended for use with fieldless enums, and for 84 /// these the correct integer type is easy: The enum should have a 85 /// `#[repr(Int)]` or `#[repr(C)]` attribute, (if it does not, it is 86 /// *unsound* to implement `Contiguous`!). 87 /// 88 /// - For `#[repr(Int)]`, use the listed `Int`. e.g. `#[repr(u8)]` should 89 /// use `type Int = u8`. 90 /// 91 /// - For `#[repr(C)]`, use whichever type the C compiler will use to 92 /// represent the given enum. This is usually `c_int` (from `std::os::raw` 93 /// or `libc`), but it's up to you to make the determination as the 94 /// implementer of the unsafe trait. 95 /// 96 /// For precise rules, see the list under "Safety" above. 97 type Int: Copy + Ord; 98 99 /// The upper *inclusive* bound for valid instances of this type. 100 const MAX_VALUE: Self::Int; 101 102 /// The lower *inclusive* bound for valid instances of this type. 103 const MIN_VALUE: Self::Int; 104 105 /// If `value` is within the range for valid instances of this type, 106 /// returns `Some(converted_value)`, otherwise, returns `None`. 107 /// 108 /// This is a trait method so that you can write `value.into_integer()` in 109 /// your code. It is a contract of this trait that if you implement 110 /// `Contiguous` on your type you **must not** override this method. 111 /// 112 /// # Panics 113 /// 114 /// We will not panic for any correct implementation of `Contiguous`, but 115 /// *may* panic if we detect an incorrect one. 116 /// 117 /// This is undefined behavior regardless, so it could have been the nasal 118 /// demons at that point anyway ;). 119 #[inline] from_integer(value: Self::Int) -> Option<Self>120 fn from_integer(value: Self::Int) -> Option<Self> { 121 // Guard against an illegal implementation of Contiguous. Annoyingly we 122 // can't rely on `transmute` to do this for us (see below), but 123 // whatever, this gets compiled into nothing in release. 124 assert!(size_of::<Self>() == size_of::<Self::Int>()); 125 if Self::MIN_VALUE <= value && value <= Self::MAX_VALUE { 126 // SAFETY: We've checked their bounds (and their size, even though 127 // they've sworn under the Oath Of Unsafe Rust that that already 128 // matched) so this is allowed by `Contiguous`'s unsafe contract. 129 // 130 // So, the `transmute_copy`. ideally we'd use transmute here, which 131 // is more obviously safe. Sadly, we can't, as these types still 132 // have unspecified sizes. 133 Some(unsafe { transmute_copy::<Self::Int, Self>(&value) }) 134 } else { 135 None 136 } 137 } 138 139 /// Perform the conversion from `C` into the underlying integral type. This 140 /// mostly exists otherwise generic code would need unsafe for the `value as 141 /// integer` 142 /// 143 /// This is a trait method so that you can write `value.into_integer()` in 144 /// your code. It is a contract of this trait that if you implement 145 /// `Contiguous` on your type you **must not** override this method. 146 /// 147 /// # Panics 148 /// 149 /// We will not panic for any correct implementation of `Contiguous`, but 150 /// *may* panic if we detect an incorrect one. 151 /// 152 /// This is undefined behavior regardless, so it could have been the nasal 153 /// demons at that point anyway ;). 154 #[inline] into_integer(self) -> Self::Int155 fn into_integer(self) -> Self::Int { 156 // Guard against an illegal implementation of Contiguous. Annoyingly we 157 // can't rely on `transmute` to do the size check for us (see 158 // `from_integer's comment`), but whatever, this gets compiled into 159 // nothing in release. Note that we don't check the result of cast 160 assert!(size_of::<Self>() == size_of::<Self::Int>()); 161 162 // SAFETY: The unsafe contract requires that these have identical 163 // representations, and that the range be entirely valid. Using 164 // transmute_copy instead of transmute here is annoying, but is required 165 // as `Self` and `Self::Int` have unspecified sizes still. 166 unsafe { transmute_copy::<Self, Self::Int>(&self) } 167 } 168 } 169 170 macro_rules! impl_contiguous { 171 ($($src:ty as $repr:ident in [$min:expr, $max:expr];)*) => {$( 172 unsafe impl Contiguous for $src { 173 type Int = $repr; 174 const MAX_VALUE: $repr = $max; 175 const MIN_VALUE: $repr = $min; 176 } 177 )*}; 178 } 179 180 impl_contiguous! { 181 bool as u8 in [0, 1]; 182 183 u8 as u8 in [0, u8::max_value()]; 184 u16 as u16 in [0, u16::max_value()]; 185 u32 as u32 in [0, u32::max_value()]; 186 u64 as u64 in [0, u64::max_value()]; 187 u128 as u128 in [0, u128::max_value()]; 188 usize as usize in [0, usize::max_value()]; 189 190 i8 as i8 in [i8::min_value(), i8::max_value()]; 191 i16 as i16 in [i16::min_value(), i16::max_value()]; 192 i32 as i32 in [i32::min_value(), i32::max_value()]; 193 i64 as i64 in [i64::min_value(), i64::max_value()]; 194 i128 as i128 in [i128::min_value(), i128::max_value()]; 195 isize as isize in [isize::min_value(), isize::max_value()]; 196 197 NonZeroU8 as u8 in [1, u8::max_value()]; 198 NonZeroU16 as u16 in [1, u16::max_value()]; 199 NonZeroU32 as u32 in [1, u32::max_value()]; 200 NonZeroU64 as u64 in [1, u64::max_value()]; 201 NonZeroU128 as u128 in [1, u128::max_value()]; 202 NonZeroUsize as usize in [1, usize::max_value()]; 203 } 204