/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zerovec-0.10.4/src/ule/plain.rs
Line | Count | Source |
1 | | // This file is part of ICU4X. For terms of use, please see the file |
2 | | // called LICENSE at the top level of the ICU4X source tree |
3 | | // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). |
4 | | |
5 | | #![allow(clippy::upper_case_acronyms)] |
6 | | //! ULE implementation for Plain Old Data types, including all sized integers. |
7 | | |
8 | | use super::*; |
9 | | use crate::impl_ule_from_array; |
10 | | use crate::ZeroSlice; |
11 | | use core::num::{NonZeroI8, NonZeroU8}; |
12 | | |
13 | | /// A u8 array of little-endian data with infallible conversions to and from &[u8]. |
14 | | #[repr(transparent)] |
15 | | #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)] |
16 | | #[allow(clippy::exhaustive_structs)] // newtype |
17 | | pub struct RawBytesULE<const N: usize>(pub [u8; N]); |
18 | | |
19 | | impl<const N: usize> RawBytesULE<N> { |
20 | | #[inline] |
21 | 0 | pub fn as_bytes(&self) -> &[u8] { |
22 | 0 | &self.0 |
23 | 0 | } |
24 | | |
25 | | #[inline] |
26 | 0 | pub fn from_byte_slice_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] { |
27 | 0 | let data = bytes.as_mut_ptr(); |
28 | 0 | let len = bytes.len() / N; |
29 | | // Safe because Self is transparent over [u8; N] |
30 | 0 | unsafe { core::slice::from_raw_parts_mut(data as *mut Self, len) } |
31 | 0 | } |
32 | | } |
33 | | |
34 | | // Safety (based on the safety checklist on the ULE trait): |
35 | | // 1. RawBytesULE does not include any uninitialized or padding bytes. |
36 | | // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant) |
37 | | // 2. RawBytesULE is aligned to 1 byte. |
38 | | // (achieved by `#[repr(transparent)]` on a type that satisfies this invariant) |
39 | | // 3. The impl of validate_byte_slice() returns an error if any byte is not valid (never). |
40 | | // 4. The impl of validate_byte_slice() returns an error if there are leftover bytes. |
41 | | // 5. The other ULE methods use the default impl. |
42 | | // 6. RawBytesULE byte equality is semantic equality |
43 | | unsafe impl<const N: usize> ULE for RawBytesULE<N> { |
44 | | #[inline] |
45 | 0 | fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> { |
46 | 0 | if bytes.len() % N == 0 { |
47 | | // Safe because Self is transparent over [u8; N] |
48 | 0 | Ok(()) |
49 | | } else { |
50 | 0 | Err(ZeroVecError::length::<Self>(bytes.len())) |
51 | | } |
52 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2> as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<_> as zerovec::ule::ULE>::validate_byte_slice |
53 | | } |
54 | | |
55 | | impl<const N: usize> From<[u8; N]> for RawBytesULE<N> { |
56 | | #[inline] |
57 | 0 | fn from(le_bytes: [u8; N]) -> Self { |
58 | 0 | Self(le_bytes) |
59 | 0 | } |
60 | | } |
61 | | |
62 | | macro_rules! impl_byte_slice_size { |
63 | | ($unsigned:ty, $size:literal) => { |
64 | | impl RawBytesULE<$size> { |
65 | | #[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($unsigned), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on the appropriately sized type.")] |
66 | | #[inline] |
67 | 0 | pub fn as_unsigned_int(&self) -> $unsigned { |
68 | 0 | <$unsigned as $crate::ule::AsULE>::from_unaligned(*self) |
69 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<8>>::as_unsigned_int Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<16>>::as_unsigned_int |
70 | | |
71 | | #[doc = concat!("Converts a `", stringify!($unsigned), "` to a `RawBytesULE`. This is equivalent to calling [`AsULE::to_unaligned()`] on the appropriately sized type.")] |
72 | | #[inline] |
73 | 0 | pub const fn from_aligned(value: $unsigned) -> Self { |
74 | 0 | Self(value.to_le_bytes()) |
75 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::from_aligned Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::from_aligned Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<8>>::from_aligned Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<16>>::from_aligned |
76 | | |
77 | | impl_ule_from_array!( |
78 | | $unsigned, |
79 | | RawBytesULE<$size>, |
80 | | RawBytesULE([0; $size]) |
81 | | ); |
82 | | } |
83 | | }; |
84 | | } |
85 | | |
86 | | macro_rules! impl_const_constructors { |
87 | | ($base:ty, $size:literal) => { |
88 | | impl ZeroSlice<$base> { |
89 | | /// This function can be used for constructing ZeroVecs in a const context, avoiding |
90 | | /// parsing checks. |
91 | | /// |
92 | | /// This cannot be generic over T because of current limitations in `const`, but if |
93 | | /// this method is needed in a non-const context, check out [`ZeroSlice::parse_byte_slice()`] |
94 | | /// instead. |
95 | | /// |
96 | | /// See [`ZeroSlice::cast()`] for an example. |
97 | 0 | pub const fn try_from_bytes(bytes: &[u8]) -> Result<&Self, ZeroVecError> { |
98 | 0 | let len = bytes.len(); |
99 | | #[allow(clippy::modulo_one)] |
100 | 0 | if len % $size == 0 { |
101 | 0 | Ok(unsafe { Self::from_bytes_unchecked(bytes) }) |
102 | | } else { |
103 | 0 | Err(ZeroVecError::InvalidLength { |
104 | 0 | ty: concat!("<const construct: ", $size, ">"), |
105 | 0 | len, |
106 | 0 | }) |
107 | | } |
108 | 0 | } Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u8>>::try_from_bytes Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u16>>::try_from_bytes Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u32>>::try_from_bytes Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u64>>::try_from_bytes Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<u128>>::try_from_bytes Unexecuted instantiation: <zerovec::zerovec::slice::ZeroSlice<bool>>::try_from_bytes |
109 | | } |
110 | | }; |
111 | | } |
112 | | |
113 | | macro_rules! impl_byte_slice_type { |
114 | | ($single_fn:ident, $type:ty, $size:literal) => { |
115 | | impl From<$type> for RawBytesULE<$size> { |
116 | | #[inline] |
117 | 0 | fn from(value: $type) -> Self { |
118 | 0 | Self(value.to_le_bytes()) |
119 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4> as core::convert::From<u32>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<8> as core::convert::From<u64>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<16> as core::convert::From<u128>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2> as core::convert::From<i16>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4> as core::convert::From<i32>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<8> as core::convert::From<i64>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<16> as core::convert::From<i128>>::from Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2> as core::convert::From<u16>>::from |
120 | | } |
121 | | impl AsULE for $type { |
122 | | type ULE = RawBytesULE<$size>; |
123 | | #[inline] |
124 | 0 | fn to_unaligned(self) -> Self::ULE { |
125 | 0 | RawBytesULE(self.to_le_bytes()) |
126 | 0 | } Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <i32 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u64 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u128 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <i16 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <i32 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <i64 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <i128 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::to_unaligned |
127 | | #[inline] |
128 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
129 | 0 | <$type>::from_le_bytes(unaligned.0) |
130 | 0 | } Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <i32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u64 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <i32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u64 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u128 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <i16 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <i32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <i64 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <i128 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u16 as zerovec::ule::AsULE>::from_unaligned |
131 | | } |
132 | | // EqULE is true because $type and RawBytesULE<$size> |
133 | | // have the same byte sequence on little-endian |
134 | | unsafe impl EqULE for $type {} |
135 | | |
136 | | impl RawBytesULE<$size> { |
137 | 0 | pub const fn $single_fn(v: $type) -> Self { |
138 | 0 | RawBytesULE(v.to_le_bytes()) |
139 | 0 | } Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<16>>::from_signed Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::from_unsigned Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<8>>::from_unsigned Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<16>>::from_unsigned Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::from_signed Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<4>>::from_signed Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<8>>::from_signed Unexecuted instantiation: <zerovec::ule::plain::RawBytesULE<2>>::from_unsigned |
140 | | } |
141 | | }; |
142 | | } |
143 | | |
144 | | macro_rules! impl_byte_slice_unsigned_type { |
145 | | ($type:ty, $size:literal) => { |
146 | | impl_byte_slice_type!(from_unsigned, $type, $size); |
147 | | }; |
148 | | } |
149 | | |
150 | | macro_rules! impl_byte_slice_signed_type { |
151 | | ($type:ty, $size:literal) => { |
152 | | impl_byte_slice_type!(from_signed, $type, $size); |
153 | | }; |
154 | | } |
155 | | |
156 | | impl_byte_slice_size!(u16, 2); |
157 | | impl_byte_slice_size!(u32, 4); |
158 | | impl_byte_slice_size!(u64, 8); |
159 | | impl_byte_slice_size!(u128, 16); |
160 | | |
161 | | impl_byte_slice_unsigned_type!(u16, 2); |
162 | | impl_byte_slice_unsigned_type!(u32, 4); |
163 | | impl_byte_slice_unsigned_type!(u64, 8); |
164 | | impl_byte_slice_unsigned_type!(u128, 16); |
165 | | |
166 | | impl_byte_slice_signed_type!(i16, 2); |
167 | | impl_byte_slice_signed_type!(i32, 4); |
168 | | impl_byte_slice_signed_type!(i64, 8); |
169 | | impl_byte_slice_signed_type!(i128, 16); |
170 | | |
171 | | impl_const_constructors!(u8, 1); |
172 | | impl_const_constructors!(u16, 2); |
173 | | impl_const_constructors!(u32, 4); |
174 | | impl_const_constructors!(u64, 8); |
175 | | impl_const_constructors!(u128, 16); |
176 | | |
177 | | // Note: The f32 and f64 const constructors currently have limited use because |
178 | | // `f32::to_le_bytes` is not yet const. |
179 | | |
180 | | impl_const_constructors!(bool, 1); |
181 | | |
182 | | // Safety (based on the safety checklist on the ULE trait): |
183 | | // 1. u8 does not include any uninitialized or padding bytes. |
184 | | // 2. u8 is aligned to 1 byte. |
185 | | // 3. The impl of validate_byte_slice() returns an error if any byte is not valid (never). |
186 | | // 4. The impl of validate_byte_slice() returns an error if there are leftover bytes (never). |
187 | | // 5. The other ULE methods use the default impl. |
188 | | // 6. u8 byte equality is semantic equality |
189 | | unsafe impl ULE for u8 { |
190 | | #[inline] |
191 | 0 | fn validate_byte_slice(_bytes: &[u8]) -> Result<(), ZeroVecError> { |
192 | 0 | Ok(()) |
193 | 0 | } Unexecuted instantiation: <u8 as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <u8 as zerovec::ule::ULE>::validate_byte_slice Unexecuted instantiation: <u8 as zerovec::ule::ULE>::validate_byte_slice |
194 | | } |
195 | | |
196 | | impl AsULE for u8 { |
197 | | type ULE = Self; |
198 | | #[inline] |
199 | 0 | fn to_unaligned(self) -> Self::ULE { |
200 | 0 | self |
201 | 0 | } Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::to_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::to_unaligned |
202 | | #[inline] |
203 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
204 | 0 | unaligned |
205 | 0 | } Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <u8 as zerovec::ule::AsULE>::from_unaligned |
206 | | } |
207 | | |
208 | | // EqULE is true because u8 is its own ULE. |
209 | | unsafe impl EqULE for u8 {} |
210 | | |
211 | | // Safety (based on the safety checklist on the ULE trait): |
212 | | // 1. NonZeroU8 does not include any uninitialized or padding bytes. |
213 | | // 2. NonZeroU8 is aligned to 1 byte. |
214 | | // 3. The impl of validate_byte_slice() returns an error if any byte is not valid (0x00). |
215 | | // 4. The impl of validate_byte_slice() returns an error if there are leftover bytes (never). |
216 | | // 5. The other ULE methods use the default impl. |
217 | | // 6. NonZeroU8 byte equality is semantic equality |
218 | | unsafe impl ULE for NonZeroU8 { |
219 | | #[inline] |
220 | 0 | fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> { |
221 | 0 | bytes.iter().try_for_each(|b| { |
222 | 0 | if *b == 0x00 { |
223 | 0 | Err(ZeroVecError::parse::<Self>()) |
224 | | } else { |
225 | 0 | Ok(()) |
226 | | } |
227 | 0 | }) |
228 | 0 | } |
229 | | } |
230 | | |
231 | | impl AsULE for NonZeroU8 { |
232 | | type ULE = Self; |
233 | | #[inline] |
234 | 0 | fn to_unaligned(self) -> Self::ULE { |
235 | 0 | self |
236 | 0 | } |
237 | | #[inline] |
238 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
239 | 0 | unaligned |
240 | 0 | } |
241 | | } |
242 | | |
243 | | unsafe impl EqULE for NonZeroU8 {} |
244 | | |
245 | | impl NicheBytes<1> for NonZeroU8 { |
246 | | const NICHE_BIT_PATTERN: [u8; 1] = [0x00]; |
247 | | } |
248 | | |
249 | | // Safety (based on the safety checklist on the ULE trait): |
250 | | // 1. i8 does not include any uninitialized or padding bytes. |
251 | | // 2. i8 is aligned to 1 byte. |
252 | | // 3. The impl of validate_byte_slice() returns an error if any byte is not valid (never). |
253 | | // 4. The impl of validate_byte_slice() returns an error if there are leftover bytes (never). |
254 | | // 5. The other ULE methods use the default impl. |
255 | | // 6. i8 byte equality is semantic equality |
256 | | unsafe impl ULE for i8 { |
257 | | #[inline] |
258 | 0 | fn validate_byte_slice(_bytes: &[u8]) -> Result<(), ZeroVecError> { |
259 | 0 | Ok(()) |
260 | 0 | } |
261 | | } |
262 | | |
263 | | impl AsULE for i8 { |
264 | | type ULE = Self; |
265 | | #[inline] |
266 | 0 | fn to_unaligned(self) -> Self::ULE { |
267 | 0 | self |
268 | 0 | } |
269 | | #[inline] |
270 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
271 | 0 | unaligned |
272 | 0 | } |
273 | | } |
274 | | |
275 | | // EqULE is true because i8 is its own ULE. |
276 | | unsafe impl EqULE for i8 {} |
277 | | |
278 | | impl AsULE for NonZeroI8 { |
279 | | type ULE = NonZeroU8; |
280 | | #[inline] |
281 | 0 | fn to_unaligned(self) -> Self::ULE { |
282 | | // Safety: NonZeroU8 and NonZeroI8 have same size |
283 | 0 | unsafe { core::mem::transmute(self) } |
284 | 0 | } |
285 | | |
286 | | #[inline] |
287 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
288 | | // Safety: NonZeroU8 and NonZeroI8 have same size |
289 | 0 | unsafe { core::mem::transmute(unaligned) } |
290 | 0 | } |
291 | | } |
292 | | |
293 | | // These impls are actually safe and portable due to Rust always using IEEE 754, see the documentation |
294 | | // on f32::from_bits: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.from_bits |
295 | | // |
296 | | // The only potential problem is that some older platforms treat signaling NaNs differently. This is |
297 | | // still quite portable, signalingness is not typically super important. |
298 | | |
299 | | impl AsULE for f32 { |
300 | | type ULE = RawBytesULE<4>; |
301 | | #[inline] |
302 | 0 | fn to_unaligned(self) -> Self::ULE { |
303 | 0 | self.to_bits().to_unaligned() |
304 | 0 | } |
305 | | #[inline] |
306 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
307 | 0 | Self::from_bits(u32::from_unaligned(unaligned)) |
308 | 0 | } Unexecuted instantiation: <f32 as zerovec::ule::AsULE>::from_unaligned Unexecuted instantiation: <f32 as zerovec::ule::AsULE>::from_unaligned |
309 | | } |
310 | | |
311 | | impl AsULE for f64 { |
312 | | type ULE = RawBytesULE<8>; |
313 | | #[inline] |
314 | 0 | fn to_unaligned(self) -> Self::ULE { |
315 | 0 | self.to_bits().to_unaligned() |
316 | 0 | } |
317 | | #[inline] |
318 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
319 | 0 | Self::from_bits(u64::from_unaligned(unaligned)) |
320 | 0 | } |
321 | | } |
322 | | |
323 | | // The from_bits documentation mentions that they have identical byte representations to integers |
324 | | // and EqULE only cares about LE systems |
325 | | unsafe impl EqULE for f32 {} |
326 | | unsafe impl EqULE for f64 {} |
327 | | |
328 | | // The bool impl is not as efficient as it could be |
329 | | // We can, in the future, have https://github.com/unicode-org/icu4x/blob/main/utils/zerovec/design_doc.md#bitpacking |
330 | | // for better bitpacking |
331 | | |
332 | | // Safety (based on the safety checklist on the ULE trait): |
333 | | // 1. bool does not include any uninitialized or padding bytes (the remaining 7 bytes in bool are by definition zero) |
334 | | // 2. bool is aligned to 1 byte. |
335 | | // 3. The impl of validate_byte_slice() returns an error if any byte is not valid (bytes that are not 0 or 1). |
336 | | // 4. The impl of validate_byte_slice() returns an error if there are leftover bytes (never). |
337 | | // 5. The other ULE methods use the default impl. |
338 | | // 6. bool byte equality is semantic equality |
339 | | unsafe impl ULE for bool { |
340 | | #[inline] |
341 | 0 | fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> { |
342 | 0 | for byte in bytes { |
343 | | // https://doc.rust-lang.org/reference/types/boolean.html |
344 | | // Rust booleans are always size 1, align 1 values with valid bit patterns 0x0 or 0x1 |
345 | 0 | if *byte > 1 { |
346 | 0 | return Err(ZeroVecError::parse::<Self>()); |
347 | 0 | } |
348 | | } |
349 | 0 | Ok(()) |
350 | 0 | } |
351 | | } |
352 | | |
353 | | impl AsULE for bool { |
354 | | type ULE = Self; |
355 | | #[inline] |
356 | 0 | fn to_unaligned(self) -> Self::ULE { |
357 | 0 | self |
358 | 0 | } |
359 | | #[inline] |
360 | 0 | fn from_unaligned(unaligned: Self::ULE) -> Self { |
361 | 0 | unaligned |
362 | 0 | } |
363 | | } |
364 | | |
365 | | // EqULE is true because bool is its own ULE. |
366 | | unsafe impl EqULE for bool {} |