1#![allow(clippy::upper_case_acronyms)]
6use super::*;
9use crate::impl_ule_from_array;
10use crate::ZeroSlice;
11use core::num::{NonZeroI8, NonZeroU8};
12
13#[repr(transparent)]
15#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
16#[allow(clippy::exhaustive_structs)] pub struct RawBytesULE<const N: usize>(pub [u8; N]);
18
19impl<const N: usize> RawBytesULE<N> {
20 #[inline]
21 pub fn as_bytes(&self) -> &[u8] {
22 &self.0
23 }
24
25 #[inline]
26 pub fn from_bytes_unchecked_mut(bytes: &mut [u8]) -> &mut [Self] {
27 let data = bytes.as_mut_ptr();
28 let len = bytes.len() / N;
29 unsafe { slice::from_raw_parts_mut(data as *mut Self, len) }
31 }
32}
33
34unsafe impl<const N: usize> ULE for RawBytesULE<N> {
44 #[inline]
45 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
46 if bytes.len() % N == 0 {
47 Ok(())
49 } else {
50 Err(UleError::length::<Self>(bytes.len()))
51 }
52 }
53}
54
55impl<const N: usize> From<[u8; N]> for RawBytesULE<N> {
56 #[inline]
57 fn from(le_bytes: [u8; N]) -> Self {
58 Self(le_bytes)
59 }
60}
61
62macro_rules! impl_numbers_with_raw_bytes_ule {
63 ($unsigned:ty, $signed:ty $(, $float:ty)?) => {
64 const _: () = assert!(size_of::<$unsigned>() == size_of::<$signed>() $(&& size_of::<$unsigned>() == size_of::<$float>())?);
65
66 impl RawBytesULE<{ size_of::<$unsigned>() }> {
67 #[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($unsigned), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on [`", stringify!($unsigned), "`].")]
68 #[inline]
69 pub const fn as_unsigned_int(&self) -> $unsigned {
70 <$unsigned>::from_le_bytes(self.0)
71 }
72
73 #[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($unsigned), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on [`", stringify!($signed), "`].")]
74 #[inline]
75 pub const fn as_signed_int(&self) -> $signed {
76 <$signed>::from_le_bytes(self.0)
77 }
78
79 $(
80 #[doc = concat!("Gets this `RawBytesULE` as a `", stringify!($float), "`. This is equivalent to calling [`AsULE::from_unaligned()`] on [`", stringify!($float), "`].")]
81 #[inline]
82 pub const fn as_float(&self) -> $float {
83 <$float>::from_le_bytes(self.0)
84 }
85 )?
86
87 #[doc = concat!("Converts a `", stringify!($unsigned), "` to a `RawBytesULE`. This is equivalent to calling [`AsULE::to_unaligned()`] on [`", stringify!($unsigned), "`].")]
88 #[inline]
89 pub const fn from_aligned(value: $unsigned) -> Self {
90 Self(value.to_le_bytes())
91 }
92
93 impl_ule_from_array!(
94 $unsigned,
95 RawBytesULE<{ size_of::<$unsigned>() }>,
96 RawBytesULE([0; { size_of::<$unsigned>() }])
97 );
98 }
99
100 impl_byte_slice_type!(from_unsigned, $unsigned);
101 impl_const_constructors!($unsigned);
102
103 impl_byte_slice_type!(from_signed, $signed);
104 impl_const_constructors!($signed);
105
106 $(
107 impl_byte_slice_type!(from_float, $float);
116 impl_const_constructors!($float);
117 )?
118};
119}
120
121macro_rules! impl_const_constructors {
122 ($base:ty) => {
123 impl ZeroSlice<$base> {
124 pub const fn try_from_bytes(bytes: &[u8]) -> Result<&Self, UleError> {
133 let len = bytes.len();
134 const STRIDE: usize = size_of::<$base>();
135 #[allow(clippy::modulo_one)]
136 if (if STRIDE <= 1 { len } else { len % STRIDE }) == 0 {
137 Ok(unsafe { Self::from_bytes_unchecked(bytes) })
138 } else {
139 Err(UleError::InvalidLength {
140 ty: concat!("<const construct: ", stringify!($base), ">"),
141 len,
142 })
143 }
144 }
145 }
146 };
147}
148
149macro_rules! impl_byte_slice_type {
150 ($single_fn:ident, $type:ty) => {
151 impl From<$type> for RawBytesULE<{ size_of::<$type>() }> {
152 #[inline]
153 fn from(value: $type) -> Self {
154 Self(value.to_le_bytes())
155 }
156 }
157 impl AsULE for $type {
158 type ULE = RawBytesULE<{ size_of::<$type>() }>;
159 #[inline]
160 fn to_unaligned(self) -> Self::ULE {
161 RawBytesULE(self.to_le_bytes())
162 }
163 #[inline]
164 fn from_unaligned(unaligned: Self::ULE) -> Self {
165 <$type>::from_le_bytes(unaligned.0)
166 }
167 }
168 unsafe impl EqULE for $type {}
171
172 impl RawBytesULE<{ size_of::<$type>() }> {
173 pub const fn $single_fn(v: $type) -> Self {
174 RawBytesULE(v.to_le_bytes())
175 }
176 }
177 };
178}
179
180impl_numbers_with_raw_bytes_ule!(u16, i16);
181impl_numbers_with_raw_bytes_ule!(u32, i32, f32);
182impl_numbers_with_raw_bytes_ule!(u64, i64, f64);
183impl_numbers_with_raw_bytes_ule!(u128, i128);
184
185unsafe impl ULE for u8 {
193 #[inline]
194 fn validate_bytes(_bytes: &[u8]) -> Result<(), UleError> {
195 Ok(())
196 }
197}
198
199impl AsULE for u8 {
200 type ULE = Self;
201 #[inline]
202 fn to_unaligned(self) -> Self::ULE {
203 self
204 }
205 #[inline]
206 fn from_unaligned(unaligned: Self::ULE) -> Self {
207 unaligned
208 }
209}
210
211unsafe impl EqULE for u8 {}
213
214impl_const_constructors!(u8);
215
216unsafe impl ULE for NonZeroU8 {
224 #[inline]
225 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
226 bytes.iter().try_for_each(|b| {
227 if *b == 0x00 {
228 Err(UleError::parse::<Self>())
229 } else {
230 Ok(())
231 }
232 })
233 }
234}
235
236impl AsULE for NonZeroU8 {
237 type ULE = Self;
238 #[inline]
239 fn to_unaligned(self) -> Self::ULE {
240 self
241 }
242 #[inline]
243 fn from_unaligned(unaligned: Self::ULE) -> Self {
244 unaligned
245 }
246}
247
248unsafe impl EqULE for NonZeroU8 {}
249
250impl NicheBytes<1> for NonZeroU8 {
251 const NICHE_BIT_PATTERN: [u8; 1] = [0x00];
252}
253
254unsafe impl ULE for i8 {
262 #[inline]
263 fn validate_bytes(_bytes: &[u8]) -> Result<(), UleError> {
264 Ok(())
265 }
266}
267
268impl AsULE for i8 {
269 type ULE = Self;
270 #[inline]
271 fn to_unaligned(self) -> Self::ULE {
272 self
273 }
274 #[inline]
275 fn from_unaligned(unaligned: Self::ULE) -> Self {
276 unaligned
277 }
278}
279
280unsafe impl EqULE for i8 {}
282
283impl AsULE for NonZeroI8 {
284 type ULE = NonZeroU8;
285 #[inline]
286 fn to_unaligned(self) -> Self::ULE {
287 unsafe { NonZeroU8::new_unchecked(self.get() as u8) }
290 }
291
292 #[inline]
293 fn from_unaligned(unaligned: Self::ULE) -> Self {
294 unsafe { NonZeroI8::new_unchecked(unaligned.get() as i8) }
297 }
298}
299
300unsafe impl ULE for bool {
312 #[inline]
313 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
314 for byte in bytes {
315 if *byte > 1 {
318 return Err(UleError::parse::<Self>());
319 }
320 }
321 Ok(())
322 }
323}
324
325impl AsULE for bool {
326 type ULE = Self;
327 #[inline]
328 fn to_unaligned(self) -> Self::ULE {
329 self
330 }
331 #[inline]
332 fn from_unaligned(unaligned: Self::ULE) -> Self {
333 unaligned
334 }
335}
336
337unsafe impl EqULE for bool {}
339
340impl_const_constructors!(bool);
341
342unsafe impl ULE for () {
350 #[inline]
351 fn validate_bytes(bytes: &[u8]) -> Result<(), UleError> {
352 if bytes.is_empty() {
353 Ok(())
354 } else {
355 Err(UleError::length::<Self>(bytes.len()))
356 }
357 }
358}
359
360impl AsULE for () {
361 type ULE = Self;
362 #[inline]
363 fn to_unaligned(self) -> Self::ULE {
364 self
365 }
366 #[inline]
367 fn from_unaligned(unaligned: Self::ULE) -> Self {
368 unaligned
369 }
370}
371
372unsafe impl EqULE for () {}
374
375impl_const_constructors!(());