1use core::{
4 concat,
5 num::{
6 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128,
7 NonZeroU16, NonZeroU32, NonZeroU64,
8 },
9};
10
11#[rustfmt::skip]
13macro_rules! define_unaligned_newtype {
14 (
15 $(#[$attr:meta])*
16 $name:ident: $endian:ident $size:literal $prim:ty
17 ) => {
18 #[allow(non_camel_case_types)]
19 #[doc = concat!(
20 "A ",
21 endian_name!($endian),
22 "-endian unaligned `",
23 stringify!($prim),
24 "` with a guaranteed size of `",
25 stringify!($size),
26 "` and alignment of `1`.",
27 )]
28 $(#[$attr])*
29 #[repr(C, packed)]
30 pub struct $name($prim);
31 };
32}
33
34macro_rules! define_unaligned_signed_integer {
35 ($name:ident: $endian:ident $size:literal $prim:ident) => {
36 define_unaligned_newtype!(
37 #[cfg_attr(
38 feature = "zerocopy-0_8",
39 derive(
40 zerocopy_derive::FromBytes,
41 zerocopy_derive::IntoBytes,
42 zerocopy_derive::Immutable,
43 zerocopy_derive::KnownLayout,
44 zerocopy_derive::Unaligned,
45 ),
46 )]
47 $name: $endian $size $prim
48 );
49 impl_integer!($name: $endian $prim);
50 impl_signed_integer_traits!($name: $endian $prim);
51 };
52}
53
54macro_rules! define_unaligned_signed_integers {
55 ($($le:ident $be:ident: $size:literal $prim:ident),* $(,)?) => {
56 $(
57 define_unaligned_signed_integer!($le: little $size $prim);
58 define_unaligned_signed_integer!($be: big $size $prim);
59 )*
60 };
61}
62
63define_unaligned_signed_integers! {
64 i16_ule i16_ube: 2 i16,
65 i32_ule i32_ube: 4 i32,
66 i64_ule i64_ube: 8 i64,
67 i128_ule i128_ube: 16 i128,
68}
69
70macro_rules! define_unaligned_unsigned_integer {
71 ($name:ident: $endian:ident $size:literal $prim:ident) => {
72 define_unaligned_newtype!(
73 #[cfg_attr(
74 feature = "zerocopy-0_8",
75 derive(
76 zerocopy_derive::FromBytes,
77 zerocopy_derive::IntoBytes,
78 zerocopy_derive::Immutable,
79 zerocopy_derive::KnownLayout,
80 zerocopy_derive::Unaligned,
81 ),
82 )]
83 $name: $endian $size $prim
84 );
85 impl_integer!($name: $endian $prim);
86 impl_unsigned_integer_traits!($name: $endian $prim);
87 }
88}
89
90macro_rules! define_unaligned_unsigned_integers {
91 ($($le:ident $be:ident: $size:literal $prim:ident),* $(,)?) => {
92 $(
93 define_unaligned_unsigned_integer!($le: little $size $prim);
94 define_unaligned_unsigned_integer!($be: big $size $prim);
95 )*
96 };
97}
98
99define_unaligned_unsigned_integers! {
100 u16_ule u16_ube: 2 u16,
101 u32_ule u32_ube: 4 u32,
102 u64_ule u64_ube: 8 u64,
103 u128_ule u128_ube: 16 u128,
104}
105
106macro_rules! define_unaligned_float {
107 ($name:ident: $endian:ident $size:literal $prim:ty as $prim_int:ty) => {
108 define_unaligned_newtype!(
109 #[cfg_attr(
110 feature = "zerocopy-0_8",
111 derive(
112 zerocopy_derive::FromBytes,
113 zerocopy_derive::IntoBytes,
114 zerocopy_derive::Immutable,
115 zerocopy_derive::KnownLayout,
116 zerocopy_derive::Unaligned,
117 ),
118 )]
119 $name: $endian $size $prim
120 );
121 impl_float!($name: $endian $prim as $prim_int);
122 };
123}
124
125macro_rules! define_unaligned_floats {
126 ($(
127 $le:ident $be:ident:
128 $size:literal $prim:ty as $prim_int:ty
129 ),* $(,)?) => {
130 $(
131 define_unaligned_float!($le: little $size $prim as $prim_int);
132 define_unaligned_float!($be: big $size $prim as $prim_int);
133 )*
134 };
135}
136
137define_unaligned_floats! {
138 f32_ule f32_ube: 4 f32 as u32,
139 f64_ule f64_ube: 8 f64 as u64,
140}
141
142macro_rules! define_unaligned_char {
143 ($name:ident: $endian:ident) => {
144 define_unaligned_newtype!(
145 #[cfg_attr(
146 feature = "zerocopy-0_8",
147 derive(
148 zerocopy_derive::IntoBytes,
157 zerocopy_derive::Immutable,
158 zerocopy_derive::KnownLayout,
159 zerocopy_derive::Unaligned,
160 ),
161 )]
162 $name: $endian 4 u32
163 );
164 impl_char!($name: $endian);
165
166 #[cfg(feature = "bytecheck")]
167 unsafe impl<C> bytecheck::CheckBytes<C> for $name
170 where
171 C: bytecheck::rancor::Fallible + ?Sized,
172 C::Error: bytecheck::rancor::Trace,
173 char: bytecheck::CheckBytes<C>,
174 {
175 #[inline]
176 unsafe fn check_bytes(
177 value: *const Self,
178 context: &mut C,
179 ) -> Result<(), C::Error> {
180 use bytecheck::rancor::ResultExt as _;
181
182 let u = unsafe {
186 value.cast::<u32>().read_unaligned()
187 };
188 let c = swap_endian!($endian u);
189 unsafe {
192 char::check_bytes(&c as *const u32 as *const char, context)
193 .with_trace(|| $crate::context::ValueCheckContext {
194 inner_name: "char",
195 outer_name: core::stringify!($name),
196 })
197 }
198 }
199 }
200 };
201}
202
203define_unaligned_char!(char_ule: little);
204define_unaligned_char!(char_ube: big);
205
206macro_rules! define_unaligned_nonzero {
207 ($name:ident: $endian:ident $size:literal $prim:ty as $prim_int:ty) => {
208 define_unaligned_newtype!($name: $endian $size $prim);
209 impl_nonzero!($name: $endian $prim as $prim_int);
210
211 #[cfg(feature = "bytecheck")]
212 unsafe impl<C> bytecheck::CheckBytes<C> for $name
215 where
216 C: bytecheck::rancor::Fallible + ?Sized,
217 C::Error: bytecheck::rancor::Trace,
218 $prim: bytecheck::CheckBytes<C>,
219 {
220 #[inline]
221 unsafe fn check_bytes(
222 value: *const Self,
223 context: &mut C,
224 ) -> Result<(), C::Error> {
225 use bytecheck::rancor::ResultExt as _;
226
227 let value = unsafe {
231 value.cast::<$prim_int>().read_unaligned()
232 };
233 let ptr = (&value as *const $prim_int).cast::<$prim>();
234 unsafe {
237 <$prim>::check_bytes(ptr, context)
238 .with_trace(|| $crate::context::ValueCheckContext {
239 inner_name: core::stringify!($prim),
240 outer_name: core::stringify!($name),
241 })
242 }
243 }
244 }
245 };
246}
247
248macro_rules! define_unaligned_nonzeros {
249 ($(
250 $le:ident $be:ident:
251 $size:literal $prim:ty as $prim_int:ty
252 ),* $(,)?) => {
253 $(
254 define_unaligned_nonzero!($le: little $size $prim as $prim_int);
255 define_unaligned_nonzero!($be: big $size $prim as $prim_int);
256 )*
257 }
258}
259
260define_unaligned_nonzeros! {
261 NonZeroI16_ule NonZeroI16_ube: 2 NonZeroI16 as i16,
262 NonZeroI32_ule NonZeroI32_ube: 2 NonZeroI32 as i32,
263 NonZeroI64_ule NonZeroI64_ube: 4 NonZeroI64 as i64,
264 NonZeroI128_ule NonZeroI128_ube: 4 NonZeroI128 as i128,
265 NonZeroU16_ule NonZeroU16_ube: 8 NonZeroU16 as u16,
266 NonZeroU32_ule NonZeroU32_ube: 8 NonZeroU32 as u32,
267 NonZeroU64_ule NonZeroU64_ube: 16 NonZeroU64 as u64,
268 NonZeroU128_ule NonZeroU128_ube: 16 NonZeroU128 as u128,
269}
270
271#[cfg(test)]
272mod tests {
273 use core::mem::transmute;
274
275 use super::*;
276
277 #[test]
278 fn signed_integers() {
279 assert_size_align! {
280 i16_ube 2 1,
281 i16_ule 2 1,
282 i32_ube 4 1,
283 i32_ule 4 1,
284 i64_ube 8 1,
285 i64_ule 8 1,
286 i128_ube 16 1,
287 i128_ule 16 1,
288 }
289
290 unsafe {
291 assert_eq!(
293 [0x02, 0x01],
294 transmute::<_, [u8; 2]>(i16_ule::from_native(0x0102)),
295 );
296 assert_eq!(
297 [0x01, 0x02],
298 transmute::<_, [u8; 2]>(i16_ube::from_native(0x0102)),
299 );
300
301 assert_eq!(
303 [0x04, 0x03, 0x02, 0x01],
304 transmute::<_, [u8; 4]>(i32_ule::from_native(0x01020304)),
305 );
306 assert_eq!(
307 [0x01, 0x02, 0x03, 0x04],
308 transmute::<_, [u8; 4]>(i32_ube::from_native(0x01020304)),
309 );
310
311 assert_eq!(
313 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
314 transmute::<_, [u8; 8]>(i64_ule::from_native(
315 0x0102030405060708
316 )),
317 );
318 assert_eq!(
319 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
320 transmute::<_, [u8; 8]>(i64_ube::from_native(
321 0x0102030405060708
322 )),
323 );
324
325 assert_eq!(
327 [
328 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
329 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
330 ],
331 transmute::<_, [u8; 16]>(i128_ule::from_native(
332 0x0102030405060708090a0b0c0d0e0f10
333 )),
334 );
335 assert_eq!(
336 [
337 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
338 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
339 ],
340 transmute::<_, [u8; 16]>(i128_ube::from_native(
341 0x0102030405060708090a0b0c0d0e0f10
342 )),
343 );
344 }
345 }
346
347 #[test]
348 fn unsigned_integers() {
349 assert_size_align! {
350 u16_ube 2 1,
351 u16_ule 2 1,
352 u32_ube 4 1,
353 u32_ule 4 1,
354 u64_ube 8 1,
355 u64_ule 8 1,
356 u128_ube 16 1,
357 u128_ule 16 1,
358 }
359
360 unsafe {
361 assert_eq!(
363 [0x02, 0x01],
364 transmute::<_, [u8; 2]>(u16_ule::from_native(0x0102)),
365 );
366 assert_eq!(
367 [0x01, 0x02],
368 transmute::<_, [u8; 2]>(u16_ube::from_native(0x0102)),
369 );
370
371 assert_eq!(
373 [0x04, 0x03, 0x02, 0x01],
374 transmute::<_, [u8; 4]>(u32_ule::from_native(0x01020304)),
375 );
376 assert_eq!(
377 [0x01, 0x02, 0x03, 0x04],
378 transmute::<_, [u8; 4]>(u32_ube::from_native(0x01020304)),
379 );
380
381 assert_eq!(
383 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
384 transmute::<_, [u8; 8]>(u64_ule::from_native(
385 0x0102030405060708
386 )),
387 );
388 assert_eq!(
389 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
390 transmute::<_, [u8; 8]>(u64_ube::from_native(
391 0x0102030405060708
392 )),
393 );
394
395 assert_eq!(
397 [
398 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
399 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
400 ],
401 transmute::<_, [u8; 16]>(u128_ule::from_native(
402 0x0102030405060708090a0b0c0d0e0f10
403 )),
404 );
405 assert_eq!(
406 [
407 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
408 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
409 ],
410 transmute::<_, [u8; 16]>(u128_ube::from_native(
411 0x0102030405060708090a0b0c0d0e0f10
412 )),
413 );
414 }
415 }
416
417 #[test]
418 fn floats() {
419 assert_size_align! {
420 f32_ube 4 1,
421 f32_ule 4 1,
422 f64_ube 8 1,
423 f64_ule 8 1,
424 }
425
426 unsafe {
427 assert_eq!(
429 [0xdb, 0x0f, 0x49, 0x40],
430 transmute::<_, [u8; 4]>(f32_ule::from_native(
431 core::f32::consts::PI
432 )),
433 );
434 assert_eq!(
435 [0x40, 0x49, 0x0f, 0xdb],
436 transmute::<_, [u8; 4]>(f32_ube::from_native(
437 core::f32::consts::PI
438 )),
439 );
440
441 assert_eq!(
443 [0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
444 transmute::<_, [u8; 8]>(f64_ule::from_native(
445 core::f64::consts::PI
446 )),
447 );
448 assert_eq!(
449 [0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18],
450 transmute::<_, [u8; 8]>(f64_ube::from_native(
451 core::f64::consts::PI
452 )),
453 );
454
455 assert_eq!(
457 [0x89, 0xf3, 0x01, 0x00],
458 transmute::<_, [u8; 4]>(char_ule::from_native('🎉')),
459 );
460 assert_eq!(
461 [0x00, 0x01, 0xf3, 0x89],
462 transmute::<_, [u8; 4]>(char_ube::from_native('🎉')),
463 );
464 }
465 }
466
467 #[test]
468 fn signed_non_zero() {
469 assert_size_align! {
470 NonZeroI16_ule 2 1,
471 NonZeroI16_ube 2 1,
472 NonZeroI32_ule 4 1,
473 NonZeroI32_ube 4 1,
474 NonZeroI64_ule 8 1,
475 NonZeroI64_ube 8 1,
476 NonZeroI128_ule 16 1,
477 NonZeroI128_ube 16 1,
478 }
479
480 unsafe {
481 assert_eq!(
483 [0x02, 0x01],
484 transmute::<_, [u8; 2]>(NonZeroI16_ule::new_unchecked(0x0102)),
485 );
486 assert_eq!(
487 [0x01, 0x02],
488 transmute::<_, [u8; 2]>(NonZeroI16_ube::new_unchecked(0x0102)),
489 );
490
491 assert_eq!(
493 [0x04, 0x03, 0x02, 0x01],
494 transmute::<_, [u8; 4]>(NonZeroI32_ule::new_unchecked(
495 0x01020304
496 )),
497 );
498 assert_eq!(
499 [0x01, 0x02, 0x03, 0x04],
500 transmute::<_, [u8; 4]>(NonZeroI32_ube::new_unchecked(
501 0x01020304
502 )),
503 );
504
505 assert_eq!(
507 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
508 transmute::<_, [u8; 8]>(NonZeroI64_ule::new_unchecked(
509 0x0102030405060708
510 )),
511 );
512 assert_eq!(
513 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
514 transmute::<_, [u8; 8]>(NonZeroI64_ube::new_unchecked(
515 0x0102030405060708
516 )),
517 );
518
519 assert_eq!(
521 [
522 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
523 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
524 ],
525 transmute::<_, [u8; 16]>(NonZeroI128_ule::new_unchecked(
526 0x0102030405060708090a0b0c0d0e0f10
527 )),
528 );
529 assert_eq!(
530 [
531 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
532 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
533 ],
534 transmute::<_, [u8; 16]>(NonZeroI128_ube::new_unchecked(
535 0x0102030405060708090a0b0c0d0e0f10
536 )),
537 );
538 }
539 }
540
541 #[test]
542 fn unsigned_non_zero() {
543 assert_size_align! {
544 NonZeroU16_ule 2 1,
545 NonZeroU16_ube 2 1,
546 NonZeroU32_ule 4 1,
547 NonZeroU32_ube 4 1,
548 NonZeroU64_ule 8 1,
549 NonZeroU64_ube 8 1,
550 NonZeroU128_ule 16 1,
551 NonZeroU128_ube 16 1,
552 }
553
554 unsafe {
555 assert_eq!(
557 [0x02, 0x01],
558 transmute::<_, [u8; 2]>(NonZeroU16_ule::new_unchecked(0x0102)),
559 );
560 assert_eq!(
561 [0x01, 0x02],
562 transmute::<_, [u8; 2]>(NonZeroU16_ube::new_unchecked(0x0102)),
563 );
564
565 assert_eq!(
567 [0x04, 0x03, 0x02, 0x01],
568 transmute::<_, [u8; 4]>(NonZeroU32_ule::new_unchecked(
569 0x01020304
570 )),
571 );
572 assert_eq!(
573 [0x01, 0x02, 0x03, 0x04],
574 transmute::<_, [u8; 4]>(NonZeroU32_ube::new_unchecked(
575 0x01020304
576 )),
577 );
578
579 assert_eq!(
581 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
582 transmute::<_, [u8; 8]>(NonZeroU64_ule::new_unchecked(
583 0x0102030405060708
584 )),
585 );
586 assert_eq!(
587 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
588 transmute::<_, [u8; 8]>(NonZeroU64_ube::new_unchecked(
589 0x0102030405060708
590 )),
591 );
592
593 assert_eq!(
595 [
596 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
597 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
598 ],
599 transmute::<_, [u8; 16]>(NonZeroU128_ule::new_unchecked(
600 0x0102030405060708090a0b0c0d0e0f10
601 )),
602 );
603 assert_eq!(
604 [
605 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
606 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
607 ],
608 transmute::<_, [u8; 16]>(NonZeroU128_ube::new_unchecked(
609 0x0102030405060708090a0b0c0d0e0f10
610 )),
611 );
612 }
613 }
614}