1#![doc = include_str!("../example.md")]
23#![no_std]
24#![deny(
25 future_incompatible,
26 missing_docs,
27 nonstandard_style,
28 unsafe_op_in_unsafe_fn,
29 unused,
30 warnings,
31 clippy::all,
32 clippy::missing_safety_doc,
33 clippy::undocumented_unsafe_blocks,
34 rustdoc::broken_intra_doc_links,
35 rustdoc::missing_crate_level_docs
36)]
37#![cfg_attr(all(docsrs, not(doctest)), feature(doc_cfg))]
38
39#[macro_use]
40mod common;
41#[cfg(feature = "bytecheck")]
42mod context;
43#[macro_use]
44mod traits;
45#[macro_use]
46mod util;
47
48pub mod unaligned;
49
50#[cfg(target_has_atomic = "16")]
51use core::sync::atomic::{AtomicI16, AtomicU16};
52#[cfg(target_has_atomic = "32")]
53use core::sync::atomic::{AtomicI32, AtomicU32};
54#[cfg(target_has_atomic = "64")]
55use core::sync::atomic::{AtomicI64, AtomicU64};
56use core::{
57 num::{
58 NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128,
59 NonZeroU16, NonZeroU32, NonZeroU64,
60 },
61 sync::atomic::Ordering,
62};
63
64#[rustfmt::skip]
66macro_rules! define_newtype {
67 (
68 $(#[$attr:meta])*
69 $name:ident: $endian:ident $size_align:literal $prim:ty
70 ) => {
71 #[allow(non_camel_case_types)]
72 #[doc = concat!(
73 "A ",
74 endian_name!($endian),
75 "-endian `",
76 stringify!($prim),
77 "` with a guaranteed size and alignment of `",
78 stringify!($size_align),
79 "`.",
80 )]
81 $(#[$attr])*
82 #[repr(C, align($size_align))]
83 pub struct $name($prim);
84 };
85}
86
87macro_rules! define_signed_integer {
88 ($name:ident: $endian:ident $size_align:literal $prim:ident) => {
89 define_newtype!(
90 #[cfg_attr(
91 feature = "zerocopy-0_8",
92 derive(
93 zerocopy_derive::FromBytes,
94 zerocopy_derive::IntoBytes,
95 zerocopy_derive::Immutable,
96 zerocopy_derive::KnownLayout,
97 ),
98 )]
99 $name: $endian $size_align $prim
100 );
101 impl_integer!($name: $endian $prim);
102 impl_signed_integer_traits!($name: $endian $prim);
103 };
104}
105
106macro_rules! define_signed_integers {
107 ($($le:ident $be:ident: $size_align:literal $prim:ident),* $(,)?) => {
108 $(
109 define_signed_integer!($le: little $size_align $prim);
110 define_signed_integer!($be: big $size_align $prim);
111 )*
112 };
113}
114
115define_signed_integers! {
116 i16_le i16_be: 2 i16,
117 i32_le i32_be: 4 i32,
118 i64_le i64_be: 8 i64,
119 i128_le i128_be: 16 i128,
120}
121
122macro_rules! define_unsigned_integer {
123 ($name:ident: $endian:ident $size_align:literal $prim:ident) => {
124 define_newtype!(
125 #[cfg_attr(
126 feature = "zerocopy-0_8",
127 derive(
128 zerocopy_derive::FromBytes,
129 zerocopy_derive::IntoBytes,
130 zerocopy_derive::Immutable,
131 zerocopy_derive::KnownLayout,
132 ),
133 )]
134 $name: $endian $size_align $prim
135 );
136 impl_integer!($name: $endian $prim);
137 impl_unsigned_integer_traits!($name: $endian $prim);
138 }
139}
140
141macro_rules! define_unsigned_integers {
142 ($($le:ident $be:ident: $size_align:literal $prim:ident),* $(,)?) => {
143 $(
144 define_unsigned_integer!($le: little $size_align $prim);
145 define_unsigned_integer!($be: big $size_align $prim);
146 )*
147 };
148}
149
150define_unsigned_integers! {
151 u16_le u16_be: 2 u16,
152 u32_le u32_be: 4 u32,
153 u64_le u64_be: 8 u64,
154 u128_le u128_be: 16 u128,
155}
156
157macro_rules! define_float {
158 (
159 $name:ident:
160 $endian:ident $size_align:literal $prim:ty as $prim_int:ty
161 ) => {
162 define_newtype!(
163 #[cfg_attr(
164 feature = "zerocopy-0_8",
165 derive(
166 zerocopy_derive::FromBytes,
167 zerocopy_derive::IntoBytes,
168 zerocopy_derive::Immutable,
169 zerocopy_derive::KnownLayout,
170 ),
171 )]
172 $name: $endian $size_align $prim
173 );
174 impl_float!($name: $endian $prim as $prim_int);
175 };
176}
177
178macro_rules! define_floats {
179 ($(
180 $le:ident $be:ident:
181 $size_align:literal $prim:ty as $prim_int:ty
182 ),* $(,)?) => {
183 $(
184 define_float!($le: little $size_align $prim as $prim_int);
185 define_float!($be: big $size_align $prim as $prim_int);
186 )*
187 };
188}
189
190define_floats! {
191 f32_le f32_be: 4 f32 as u32,
192 f64_le f64_be: 8 f64 as u64,
193}
194
195macro_rules! define_char {
196 ($name:ident: $endian:ident) => {
197 define_newtype!(
198 #[cfg_attr(
199 feature = "zerocopy-0_8",
200 derive(
201 zerocopy_derive::IntoBytes,
210 zerocopy_derive::Immutable,
211 zerocopy_derive::KnownLayout,
212 ),
213 )]
214 $name: $endian 4 u32
215 );
216 impl_char!($name: $endian);
217
218 #[cfg(feature = "bytecheck")]
219 unsafe impl<C> bytecheck::CheckBytes<C> for $name
222 where
223 C: bytecheck::rancor::Fallible + ?Sized,
224 C::Error: bytecheck::rancor::Trace,
225 char: bytecheck::CheckBytes<C>,
226 {
227 #[inline]
228 unsafe fn check_bytes(
229 value: *const Self,
230 context: &mut C,
231 ) -> Result<(), C::Error> {
232 use bytecheck::rancor::ResultExt as _;
233
234 let u = unsafe { *value.cast::<u32>() };
237 let c = swap_endian!($endian u);
238 unsafe {
241 char::check_bytes(&c as *const u32 as *const char, context)
242 .with_trace(|| $crate::context::ValueCheckContext {
243 inner_name: "char",
244 outer_name: core::stringify!($name),
245 })
246 }
247 }
248 }
249 };
250}
251
252define_char!(char_le: little);
253define_char!(char_be: big);
254
255macro_rules! define_nonzero {
256 (
257 $name:ident:
258 $endian:ident $size_align:literal $prim:ty as $prim_int:ty
259 ) => {
260 define_newtype!(
261 #[cfg_attr(
262 feature = "zerocopy-0_8",
263 derive(
264 zerocopy_derive::TryFromBytes,
265 zerocopy_derive::IntoBytes,
266 zerocopy_derive::Immutable,
267 zerocopy_derive::KnownLayout,
268 ),
269 )]
270 $name: $endian $size_align $prim
271 );
272 impl_nonzero!($name: $endian $prim as $prim_int);
273
274 #[cfg(feature = "bytecheck")]
275 unsafe impl<C> bytecheck::CheckBytes<C> for $name
278 where
279 C: bytecheck::rancor::Fallible + ?Sized,
280 C::Error: bytecheck::rancor::Trace,
281 $prim: bytecheck::CheckBytes<C>,
282 {
283 #[inline]
284 unsafe fn check_bytes(
285 value: *const Self,
286 context: &mut C,
287 ) -> Result<(), C::Error> {
288 use bytecheck::rancor::ResultExt as _;
289
290 unsafe {
295 <$prim>::check_bytes(value.cast(), context)
296 .with_trace(|| $crate::context::ValueCheckContext {
297 inner_name: core::stringify!($prim),
298 outer_name: core::stringify!($name),
299 })
300 }
301 }
302 }
303 };
304}
305
306macro_rules! define_nonzeros {
307 ($(
308 $le:ident $be:ident:
309 $size_align:literal $prim:ty as $prim_int:ty
310 ),* $(,)?) => {
311 $(
312 define_nonzero!($le: little $size_align $prim as $prim_int);
313 define_nonzero!($be: big $size_align $prim as $prim_int);
314 )*
315 }
316}
317
318define_nonzeros! {
319 NonZeroI16_le NonZeroI16_be: 2 NonZeroI16 as i16,
320 NonZeroI32_le NonZeroI32_be: 4 NonZeroI32 as i32,
321 NonZeroI64_le NonZeroI64_be: 8 NonZeroI64 as i64,
322 NonZeroI128_le NonZeroI128_be: 16 NonZeroI128 as i128,
323 NonZeroU16_le NonZeroU16_be: 2 NonZeroU16 as u16,
324 NonZeroU32_le NonZeroU32_be: 4 NonZeroU32 as u32,
325 NonZeroU64_le NonZeroU64_be: 8 NonZeroU64 as u64,
326 NonZeroU128_le NonZeroU128_be: 16 NonZeroU128 as u128,
327}
328
329#[allow(dead_code)]
330const fn fetch_ordering(order: Ordering) -> Ordering {
331 match order {
332 Ordering::Relaxed => Ordering::Relaxed,
333 Ordering::Release => Ordering::Relaxed,
334 Ordering::Acquire => Ordering::Acquire,
335 Ordering::AcqRel => Ordering::Acquire,
336 Ordering::SeqCst => Ordering::SeqCst,
337 order => order,
338 }
339}
340
341#[cfg(any(
342 target_has_atomic = "16",
343 target_has_atomic = "32",
344 target_has_atomic = "64",
345))]
346macro_rules! define_atomic {
347 (
348 $name:ident:
349 $endian:ident $size_align:literal $prim:ty as $prim_int:ty
350 ) => {
351 define_newtype!(
352 #[cfg_attr(
353 feature = "zerocopy-0_8",
354 derive(
355 zerocopy_derive::FromBytes,
356 zerocopy_derive::IntoBytes,
357 zerocopy_derive::KnownLayout,
358 ),
359 )]
360 $name: $endian $size_align $prim
361 );
362
363 impl $name {
364 #[doc = concat!(
365 "Returns a `",
366 stringify!($name),
367 "` containing `value`.",
368 )]
369 #[inline]
370 pub const fn new(value: $prim_int) -> Self {
371 Self(<$prim>::new(swap_endian!($endian value)))
372 }
373 }
374
375 unsafe_impl_check_bytes_noop!(for $name);
378
379 impl $name {
380 #[doc = concat!(
384 "See [`",
385 stringify!($prim),
386 "::compare_exchange`] for more information.",
387 )]
388 #[inline]
389 pub fn compare_exchange(
390 &self,
391 current: $prim_int,
392 new: $prim_int,
393 success: Ordering,
394 failure: Ordering,
395 ) -> Result<$prim_int, $prim_int> {
396 match self.0.compare_exchange(
397 swap_endian!($endian current),
398 swap_endian!($endian new),
399 success,
400 failure,
401 ) {
402 Ok(x) => Ok(swap_endian!($endian x)),
403 Err(x) => Err(swap_endian!($endian x)),
404 }
405 }
406
407 #[doc = concat!(
411 "See [`",
412 stringify!($prim),
413 "::compare_exchange_weak`] for more information.",
414 )]
415 #[inline]
416 pub fn compare_exchange_weak(
417 &self,
418 current: $prim_int,
419 new: $prim_int,
420 success: Ordering,
421 failure: Ordering,
422 ) -> Result<$prim_int, $prim_int> {
423 match self.0.compare_exchange_weak(
424 swap_endian!($endian current),
425 swap_endian!($endian new),
426 success,
427 failure,
428 ) {
429 Ok(x) => Ok(swap_endian!($endian x)),
430 Err(x) => Err(swap_endian!($endian x)),
431 }
432 }
433
434 #[doc = concat!(
437 "Because addition is not an endian-agnostic operation, ",
438 "`fetch_add` is implemented in terms of [`",
439 stringify!($prim),
440 "::compare_exchange_weak`] on ",
441 opposite_endian_name!($endian),
442 "-endian targets. This may result in worse performance on ",
443 "those targets.",
444 )]
445 #[doc = concat!(
447 "See [`",
448 stringify!($prim),
449 "::fetch_add`] for more information.",
450 )]
451 #[inline]
452 pub fn fetch_add(
453 &self,
454 val: $prim_int,
455 order: Ordering,
456 ) -> $prim_int {
457 if_native_endian!(
458 $endian
459 self.0.fetch_add(val, order),
460 self.fetch_update_fast(
461 order,
462 fetch_ordering(order),
463 |x| x + val,
464 ),
465 )
466 }
467
468 #[doc = concat!(
471 "See [`",
472 stringify!($prim),
473 "::fetch_and`] for more information.",
474 )]
475 #[inline]
476 pub fn fetch_and(
477 &self,
478 val: $prim_int,
479 order: Ordering,
480 ) -> $prim_int {
481 let val = swap_endian!($endian val);
482 swap_endian!($endian self.0.fetch_and(val, order))
483 }
484
485 #[doc = concat!(
488 "Because maximum is not an endian-agnostic operation, ",
489 "`fetch_max` is implemented in terms of [`",
490 stringify!($prim),
491 "::compare_exchange_weak`] on ",
492 opposite_endian_name!($endian),
493 "-endian targets. This may result in worse performance on ",
494 "those targets.",
495 )]
496 #[doc = concat!(
498 "See [`",
499 stringify!($prim),
500 "::fetch_max`] for more information.",
501 )]
502 #[inline]
503 pub fn fetch_max(
504 &self,
505 val: $prim_int,
506 order: Ordering,
507 ) -> $prim_int {
508 if_native_endian!(
509 $endian
510 self.0.fetch_max(val, order),
511 self.fetch_update_fast(
512 order,
513 fetch_ordering(order),
514 |x| <$prim_int>::max(x, val),
515 ),
516 )
517 }
518
519 #[doc = concat!(
522 "Because minimum is not an endian-agnostic operation, ",
523 "`fetch_min` is implemented in terms of [`",
524 stringify!($prim),
525 "::compare_exchange_weak`] on ",
526 opposite_endian_name!($endian),
527 "-endian targets. This may result in worse performance on ",
528 "those targets.",
529 )]
530 #[doc = concat!(
532 "See [`",
533 stringify!($prim),
534 "::fetch_min`] for more information.",
535 )]
536 #[inline]
537 pub fn fetch_min(
538 &self,
539 val: $prim_int,
540 order: Ordering,
541 ) -> $prim_int {
542 if_native_endian!(
543 $endian
544 self.0.fetch_min(val, order),
545 self.fetch_update_fast(
546 order,
547 fetch_ordering(order),
548 |x| <$prim_int>::min(x, val),
549 ),
550 )
551 }
552
553 #[doc = concat!(
556 "See [`",
557 stringify!($prim),
558 "::fetch_nand`] for more information.",
559 )]
560 #[inline]
561 pub fn fetch_nand(
562 &self,
563 val: $prim_int,
564 order: Ordering,
565 ) -> $prim_int {
566 let val = swap_endian!($endian val);
567 swap_endian!($endian self.0.fetch_nand(val, order))
568 }
569
570 #[doc = concat!(
573 "See [`",
574 stringify!($prim),
575 "::fetch_or`] for more information.",
576 )]
577 #[inline]
578 pub fn fetch_or(
579 &self,
580 val: $prim_int,
581 order: Ordering,
582 ) -> $prim_int {
583 let val = swap_endian!($endian val);
584 swap_endian!($endian self.0.fetch_or(val, order))
585 }
586
587 #[doc = concat!(
590 "Because subtraction is not an endian-agnostic operation, ",
591 "`fetch_sub` is implemented in terms of [`",
592 stringify!($prim),
593 "::compare_exchange_weak`] on ",
594 opposite_endian_name!($endian),
595 "-endian targets. This may result in worse performance on ",
596 "those targets.",
597 )]
598 #[doc = concat!(
600 "See [`",
601 stringify!($prim),
602 "::fetch_sub`] for more information.",
603 )]
604 #[inline]
605 pub fn fetch_sub(
606 &self,
607 val: $prim_int,
608 order: Ordering,
609 ) -> $prim_int {
610 if_native_endian!(
611 $endian
612 self.0.fetch_sub(val, order),
613 self.fetch_update_fast(
614 order,
615 fetch_ordering(order),
616 |x| x - val,
617 ),
618 )
619 }
620
621 #[allow(dead_code)]
622 #[inline(always)]
623 fn fetch_update_fast<F: Fn($prim_int) -> $prim_int>(
624 &self,
625 set_order: Ordering,
626 fetch_order: Ordering,
627 f: F,
628 ) -> $prim_int {
629 let mut prev = self.load(fetch_order);
630 loop {
631 let next = f(prev);
632 match self.compare_exchange_weak(
633 prev,
634 next,
635 set_order,
636 fetch_order,
637 ) {
638 Ok(x) => break x,
639 Err(next_prev) => {
640 prev = next_prev;
641 }
642 }
643 }
644 }
645
646 #[doc = concat!(
651 "See [`",
652 stringify!($prim),
653 "::fetch_update`] for more information.",
654 )]
655 #[inline]
656 pub fn fetch_update<F: FnMut($prim_int) -> Option<$prim_int>>(
657 &self,
658 set_order: Ordering,
659 fetch_order: Ordering,
660 mut f: F,
661 ) -> Result<$prim_int, $prim_int> {
662 self.0.fetch_update(set_order, fetch_order, |x| {
663 f(swap_endian!($endian x)).map(|y| swap_endian!($endian y))
664 })
665 }
666
667 #[doc = concat!(
670 "See [`",
671 stringify!($prim),
672 "::fetch_xor`] for more information.",
673 )]
674 #[inline]
675 pub fn fetch_xor(
676 &self,
677 val: $prim_int,
678 order: Ordering,
679 ) -> $prim_int {
680 let val = swap_endian!($endian val);
681 swap_endian!($endian self.0.fetch_xor(val, order))
682 }
683
684 #[doc = concat!(
687 "See [`",
688 stringify!($prim),
689 "::into_inner`] for more information.",
690 )]
691 #[inline]
692 pub fn into_inner(self) -> $prim_int {
693 swap_endian!($endian self.0.into_inner())
694 }
695
696 #[doc = concat!(
699 "See [`",
700 stringify!($prim),
701 "::load`] for more information.",
702 )]
703 #[inline]
704 pub fn load(&self, order: Ordering) -> $prim_int {
705 swap_endian!($endian self.0.load(order))
706 }
707
708 #[doc = concat!(
711 "See [`",
712 stringify!($prim),
713 "::store`] for more information.",
714 )]
715 #[inline]
716 pub fn store(&self, val: $prim_int, order: Ordering) {
717 self.0.store(swap_endian!($endian val), order);
718 }
719
720 #[doc = concat!(
724 "See [`",
725 stringify!($prim),
726 "::swap`] for more information.",
727 )]
728 #[inline]
729 pub fn swap(&self, val: $prim_int, order: Ordering) -> $prim_int {
730 let val = swap_endian!($endian val);
731 swap_endian!($endian self.0.swap(val, order))
732 }
733 }
734
735 impl core::fmt::Debug for $name {
736 #[inline]
737 fn fmt(
738 &self,
739 f: &mut core::fmt::Formatter<'_>,
740 ) -> core::fmt::Result {
741 swap_endian!($endian self.load(Ordering::Relaxed)).fmt(f)
742 }
743 }
744
745 impl Default for $name {
746 #[inline]
747 fn default() -> Self {
748 Self::new(<$prim_int>::default())
749 }
750 }
751
752 impl From<$prim_int> for $name {
753 #[inline]
754 fn from(value: $prim_int) -> Self {
755 Self::new(value)
756 }
757 }
758 }
759}
760
761#[cfg(any(
762 target_has_atomic = "16",
763 target_has_atomic = "32",
764 target_has_atomic = "64",
765))]
766macro_rules! define_atomics {
767 ($(
768 $le:ident $be:ident:
769 $size_align:literal $prim:ty as $prim_int:ty
770 ),* $(,)?) => {
771 $(
772 define_atomic!($le: little $size_align $prim as $prim_int);
773 define_atomic!($be: big $size_align $prim as $prim_int);
774 )*
775 }
776}
777
778#[cfg(target_has_atomic = "16")]
779define_atomics! {
780 AtomicI16_le AtomicI16_be: 2 AtomicI16 as i16,
781 AtomicU16_le AtomicU16_be: 2 AtomicU16 as u16,
782}
783
784#[cfg(target_has_atomic = "32")]
785define_atomics! {
786 AtomicI32_le AtomicI32_be: 4 AtomicI32 as i32,
787 AtomicU32_le AtomicU32_be: 4 AtomicU32 as u32,
788}
789
790#[cfg(target_has_atomic = "64")]
791define_atomics! {
792 AtomicI64_le AtomicI64_be: 8 AtomicI64 as i64,
793 AtomicU64_le AtomicU64_be: 8 AtomicU64 as u64,
794}
795
796#[cfg(test)]
797mod tests {
798 use core::mem::transmute;
799
800 use super::*;
801
802 #[test]
803 fn signed_integers() {
804 assert_size_align! {
805 i16_be 2 2,
806 i16_le 2 2,
807 i32_be 4 4,
808 i32_le 4 4,
809 i64_be 8 8,
810 i64_le 8 8,
811 i128_be 16 16,
812 i128_le 16 16,
813 }
814
815 unsafe {
816 assert_eq!(
818 [0x02, 0x01],
819 transmute::<_, [u8; 2]>(i16_le::from_native(0x0102)),
820 );
821 assert_eq!(
822 [0x01, 0x02],
823 transmute::<_, [u8; 2]>(i16_be::from_native(0x0102)),
824 );
825
826 assert_eq!(
828 [0x04, 0x03, 0x02, 0x01],
829 transmute::<_, [u8; 4]>(i32_le::from_native(0x01020304)),
830 );
831 assert_eq!(
832 [0x01, 0x02, 0x03, 0x04],
833 transmute::<_, [u8; 4]>(i32_be::from_native(0x01020304)),
834 );
835
836 assert_eq!(
838 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
839 transmute::<_, [u8; 8]>(i64_le::from_native(
840 0x0102030405060708
841 )),
842 );
843 assert_eq!(
844 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
845 transmute::<_, [u8; 8]>(i64_be::from_native(
846 0x0102030405060708
847 )),
848 );
849
850 assert_eq!(
852 [
853 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
854 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
855 ],
856 transmute::<_, [u8; 16]>(i128_le::from_native(
857 0x0102030405060708090a0b0c0d0e0f10
858 )),
859 );
860 assert_eq!(
861 [
862 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
863 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
864 ],
865 transmute::<_, [u8; 16]>(i128_be::from_native(
866 0x0102030405060708090a0b0c0d0e0f10
867 )),
868 );
869 }
870 }
871
872 #[test]
873 fn unsigned_integers() {
874 assert_size_align! {
875 u16_be 2 2,
876 u16_le 2 2,
877 u32_be 4 4,
878 u32_le 4 4,
879 u64_be 8 8,
880 u64_le 8 8,
881 u128_be 16 16,
882 u128_le 16 16,
883 }
884
885 unsafe {
886 assert_eq!(
888 [0x02, 0x01],
889 transmute::<_, [u8; 2]>(u16_le::from_native(0x0102)),
890 );
891 assert_eq!(
892 [0x01, 0x02],
893 transmute::<_, [u8; 2]>(u16_be::from_native(0x0102)),
894 );
895
896 assert_eq!(
898 [0x04, 0x03, 0x02, 0x01],
899 transmute::<_, [u8; 4]>(u32_le::from_native(0x01020304)),
900 );
901 assert_eq!(
902 [0x01, 0x02, 0x03, 0x04],
903 transmute::<_, [u8; 4]>(u32_be::from_native(0x01020304)),
904 );
905
906 assert_eq!(
908 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
909 transmute::<_, [u8; 8]>(u64_le::from_native(
910 0x0102030405060708
911 )),
912 );
913 assert_eq!(
914 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
915 transmute::<_, [u8; 8]>(u64_be::from_native(
916 0x0102030405060708
917 )),
918 );
919
920 assert_eq!(
922 [
923 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
924 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
925 ],
926 transmute::<_, [u8; 16]>(u128_le::from_native(
927 0x0102030405060708090a0b0c0d0e0f10
928 )),
929 );
930 assert_eq!(
931 [
932 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
933 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
934 ],
935 transmute::<_, [u8; 16]>(u128_be::from_native(
936 0x0102030405060708090a0b0c0d0e0f10
937 )),
938 );
939 }
940 }
941
942 #[test]
943 fn floats() {
944 assert_size_align! {
945 f32_be 4 4,
946 f32_le 4 4,
947 f64_be 8 8,
948 f64_le 8 8,
949 }
950
951 unsafe {
952 assert_eq!(
954 [0xdb, 0x0f, 0x49, 0x40],
955 transmute::<_, [u8; 4]>(f32_le::from_native(
956 core::f32::consts::PI
957 )),
958 );
959 assert_eq!(
960 [0x40, 0x49, 0x0f, 0xdb],
961 transmute::<_, [u8; 4]>(f32_be::from_native(
962 core::f32::consts::PI
963 )),
964 );
965
966 assert_eq!(
968 [0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
969 transmute::<_, [u8; 8]>(f64_le::from_native(
970 core::f64::consts::PI
971 )),
972 );
973 assert_eq!(
974 [0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18],
975 transmute::<_, [u8; 8]>(f64_be::from_native(
976 core::f64::consts::PI
977 )),
978 );
979
980 assert_eq!(
982 [0x89, 0xf3, 0x01, 0x00],
983 transmute::<_, [u8; 4]>(char_le::from_native('🎉')),
984 );
985 assert_eq!(
986 [0x00, 0x01, 0xf3, 0x89],
987 transmute::<_, [u8; 4]>(char_be::from_native('🎉')),
988 );
989 }
990 }
991
992 #[test]
993 fn signed_non_zero() {
994 assert_size_align! {
995 NonZeroI16_le 2 2,
996 NonZeroI16_be 2 2,
997 NonZeroI32_le 4 4,
998 NonZeroI32_be 4 4,
999 NonZeroI64_le 8 8,
1000 NonZeroI64_be 8 8,
1001 NonZeroI128_le 16 16,
1002 NonZeroI128_be 16 16,
1003 }
1004
1005 unsafe {
1006 assert_eq!(
1008 [0x02, 0x01],
1009 transmute::<_, [u8; 2]>(NonZeroI16_le::new_unchecked(0x0102)),
1010 );
1011 assert_eq!(
1012 [0x01, 0x02],
1013 transmute::<_, [u8; 2]>(NonZeroI16_be::new_unchecked(0x0102)),
1014 );
1015
1016 assert_eq!(
1018 [0x04, 0x03, 0x02, 0x01],
1019 transmute::<_, [u8; 4]>(NonZeroI32_le::new_unchecked(
1020 0x01020304
1021 )),
1022 );
1023 assert_eq!(
1024 [0x01, 0x02, 0x03, 0x04],
1025 transmute::<_, [u8; 4]>(NonZeroI32_be::new_unchecked(
1026 0x01020304
1027 )),
1028 );
1029
1030 assert_eq!(
1032 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1033 transmute::<_, [u8; 8]>(NonZeroI64_le::new_unchecked(
1034 0x0102030405060708
1035 )),
1036 );
1037 assert_eq!(
1038 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1039 transmute::<_, [u8; 8]>(NonZeroI64_be::new_unchecked(
1040 0x0102030405060708
1041 )),
1042 );
1043
1044 assert_eq!(
1046 [
1047 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1048 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
1049 ],
1050 transmute::<_, [u8; 16]>(NonZeroI128_le::new_unchecked(
1051 0x0102030405060708090a0b0c0d0e0f10
1052 )),
1053 );
1054 assert_eq!(
1055 [
1056 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
1057 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
1058 ],
1059 transmute::<_, [u8; 16]>(NonZeroI128_be::new_unchecked(
1060 0x0102030405060708090a0b0c0d0e0f10
1061 )),
1062 );
1063 }
1064 }
1065
1066 #[test]
1067 fn unsigned_non_zero() {
1068 assert_size_align! {
1069 NonZeroU16_le 2 2,
1070 NonZeroU16_be 2 2,
1071 NonZeroU32_le 4 4,
1072 NonZeroU32_be 4 4,
1073 NonZeroU64_le 8 8,
1074 NonZeroU64_be 8 8,
1075 NonZeroU128_le 16 16,
1076 NonZeroU128_be 16 16,
1077 }
1078
1079 unsafe {
1080 assert_eq!(
1082 [0x02, 0x01],
1083 transmute::<_, [u8; 2]>(NonZeroU16_le::new_unchecked(0x0102)),
1084 );
1085 assert_eq!(
1086 [0x01, 0x02],
1087 transmute::<_, [u8; 2]>(NonZeroU16_be::new_unchecked(0x0102)),
1088 );
1089
1090 assert_eq!(
1092 [0x04, 0x03, 0x02, 0x01],
1093 transmute::<_, [u8; 4]>(NonZeroU32_le::new_unchecked(
1094 0x01020304
1095 )),
1096 );
1097 assert_eq!(
1098 [0x01, 0x02, 0x03, 0x04],
1099 transmute::<_, [u8; 4]>(NonZeroU32_be::new_unchecked(
1100 0x01020304
1101 )),
1102 );
1103
1104 assert_eq!(
1106 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1107 transmute::<_, [u8; 8]>(NonZeroU64_le::new_unchecked(
1108 0x0102030405060708
1109 )),
1110 );
1111 assert_eq!(
1112 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1113 transmute::<_, [u8; 8]>(NonZeroU64_be::new_unchecked(
1114 0x0102030405060708
1115 )),
1116 );
1117
1118 assert_eq!(
1120 [
1121 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1122 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
1123 ],
1124 transmute::<_, [u8; 16]>(NonZeroU128_le::new_unchecked(
1125 0x0102030405060708090a0b0c0d0e0f10
1126 )),
1127 );
1128 assert_eq!(
1129 [
1130 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
1131 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
1132 ],
1133 transmute::<_, [u8; 16]>(NonZeroU128_be::new_unchecked(
1134 0x0102030405060708090a0b0c0d0e0f10
1135 )),
1136 );
1137 }
1138 }
1139
1140 #[cfg(feature = "bytecheck")]
1141 #[test]
1142 fn unaligned_non_zero() {
1143 use bytecheck::{
1144 rancor::{Failure, Strategy},
1145 CheckBytes,
1146 };
1147 use unaligned::{u32_ule, NonZeroU32_ule};
1148
1149 let zero = u32_ule::from_native(0);
1150 let ptr = (&zero as *const u32_ule).cast::<NonZeroU32_ule>();
1151 let mut unit = ();
1152 let context = Strategy::<_, Failure>::wrap(&mut unit);
1153 unsafe {
1154 <NonZeroU32_ule as CheckBytes<Strategy<(), Failure>>>::check_bytes(
1155 ptr, context,
1156 )
1157 .unwrap_err();
1158 }
1159 }
1160
1161 #[cfg(target_has_atomic = "16")]
1162 #[test]
1163 fn atomics_16() {
1164 assert_size_align! {
1165 AtomicI16_le 2 2,
1166 AtomicI16_be 2 2,
1167 AtomicU16_le 2 2,
1168 AtomicU16_be 2 2,
1169 }
1170
1171 unsafe {
1172 assert_eq!(
1174 [0x02, 0x01],
1175 transmute::<_, [u8; 2]>(AtomicI16_le::new(0x0102)),
1176 );
1177 assert_eq!(
1178 [0x01, 0x02],
1179 transmute::<_, [u8; 2]>(AtomicI16_be::new(0x0102)),
1180 );
1181
1182 assert_eq!(
1184 [0x02, 0x01],
1185 transmute::<_, [u8; 2]>(AtomicU16_le::new(0x0102)),
1186 );
1187 assert_eq!(
1188 [0x01, 0x02],
1189 transmute::<_, [u8; 2]>(AtomicU16_be::new(0x0102)),
1190 );
1191 }
1192 }
1193
1194 #[cfg(target_has_atomic = "32")]
1195 #[test]
1196 fn atomics_32() {
1197 assert_size_align! {
1198 AtomicI32_le 4 4,
1199 AtomicI32_be 4 4,
1200 AtomicU32_le 4 4,
1201 AtomicU32_be 4 4,
1202 }
1203
1204 unsafe {
1205 assert_eq!(
1207 [0x04, 0x03, 0x02, 0x01],
1208 transmute::<_, [u8; 4]>(AtomicI32_le::new(0x01020304)),
1209 );
1210 assert_eq!(
1211 [0x01, 0x02, 0x03, 0x04],
1212 transmute::<_, [u8; 4]>(AtomicI32_be::new(0x01020304)),
1213 );
1214
1215 assert_eq!(
1217 [0x04, 0x03, 0x02, 0x01],
1218 transmute::<_, [u8; 4]>(AtomicU32_le::new(0x01020304)),
1219 );
1220 assert_eq!(
1221 [0x01, 0x02, 0x03, 0x04],
1222 transmute::<_, [u8; 4]>(AtomicU32_be::new(0x01020304)),
1223 );
1224 }
1225 }
1226
1227 #[cfg(target_has_atomic = "64")]
1228 #[test]
1229 fn atomics_64() {
1230 assert_size_align! {
1231 AtomicI64_le 8 8,
1232 AtomicI64_be 8 8,
1233 AtomicU64_le 8 8,
1234 AtomicU64_be 8 8,
1235 }
1236
1237 unsafe {
1238 assert_eq!(
1240 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1241 transmute::<_, [u8; 8]>(AtomicI64_le::new(0x0102030405060708)),
1242 );
1243 assert_eq!(
1244 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1245 transmute::<_, [u8; 8]>(AtomicI64_be::new(0x0102030405060708)),
1246 );
1247
1248 assert_eq!(
1250 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1251 transmute::<_, [u8; 8]>(AtomicU64_le::new(0x0102030405060708)),
1252 );
1253 assert_eq!(
1254 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1255 transmute::<_, [u8; 8]>(AtomicU64_be::new(0x0102030405060708)),
1256 );
1257 }
1258 }
1259}