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, doc_auto_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}
219
220define_char!(char_le: little);
221define_char!(char_be: big);
222
223macro_rules! define_nonzero {
224 (
225 $name:ident:
226 $endian:ident $size_align:literal $prim:ty as $prim_int:ty
227 ) => {
228 define_newtype!(
229 #[cfg_attr(
230 feature = "zerocopy-0_8",
231 derive(
232 zerocopy_derive::TryFromBytes,
233 zerocopy_derive::IntoBytes,
234 zerocopy_derive::Immutable,
235 zerocopy_derive::KnownLayout,
236 ),
237 )]
238 $name: $endian $size_align $prim
239 );
240 impl_nonzero!($name: $endian $prim as $prim_int);
241
242 #[cfg(feature = "bytecheck")]
243 unsafe impl<C> bytecheck::CheckBytes<C> for $name
246 where
247 C: bytecheck::rancor::Fallible + ?Sized,
248 C::Error: bytecheck::rancor::Trace,
249 $prim: bytecheck::CheckBytes<C>,
250 {
251 #[inline]
252 unsafe fn check_bytes(
253 value: *const Self,
254 context: &mut C,
255 ) -> Result<(), C::Error> {
256 use bytecheck::rancor::ResultExt as _;
257
258 unsafe {
263 <$prim>::check_bytes(value.cast(), context)
264 .with_trace(|| $crate::context::ValueCheckContext {
265 inner_name: core::stringify!($prim),
266 outer_name: core::stringify!($name),
267 })
268 }
269 }
270 }
271 };
272}
273
274macro_rules! define_nonzeros {
275 ($(
276 $le:ident $be:ident:
277 $size_align:literal $prim:ty as $prim_int:ty
278 ),* $(,)?) => {
279 $(
280 define_nonzero!($le: little $size_align $prim as $prim_int);
281 define_nonzero!($be: big $size_align $prim as $prim_int);
282 )*
283 }
284}
285
286define_nonzeros! {
287 NonZeroI16_le NonZeroI16_be: 2 NonZeroI16 as i16,
288 NonZeroI32_le NonZeroI32_be: 4 NonZeroI32 as i32,
289 NonZeroI64_le NonZeroI64_be: 8 NonZeroI64 as i64,
290 NonZeroI128_le NonZeroI128_be: 16 NonZeroI128 as i128,
291 NonZeroU16_le NonZeroU16_be: 2 NonZeroU16 as u16,
292 NonZeroU32_le NonZeroU32_be: 4 NonZeroU32 as u32,
293 NonZeroU64_le NonZeroU64_be: 8 NonZeroU64 as u64,
294 NonZeroU128_le NonZeroU128_be: 16 NonZeroU128 as u128,
295}
296
297#[allow(dead_code)]
298const fn fetch_ordering(order: Ordering) -> Ordering {
299 match order {
300 Ordering::Relaxed => Ordering::Relaxed,
301 Ordering::Release => Ordering::Relaxed,
302 Ordering::Acquire => Ordering::Acquire,
303 Ordering::AcqRel => Ordering::Acquire,
304 Ordering::SeqCst => Ordering::SeqCst,
305 order => order,
306 }
307}
308
309#[cfg(any(
310 target_has_atomic = "16",
311 target_has_atomic = "32",
312 target_has_atomic = "64",
313))]
314macro_rules! define_atomic {
315 (
316 $name:ident:
317 $endian:ident $size_align:literal $prim:ty as $prim_int:ty
318 ) => {
319 define_newtype!(
320 #[cfg_attr(
321 feature = "zerocopy-0_8",
322 derive(
323 zerocopy_derive::FromBytes,
324 zerocopy_derive::IntoBytes,
325 zerocopy_derive::KnownLayout,
326 ),
327 )]
328 $name: $endian $size_align $prim
329 );
330
331 impl $name {
332 #[doc = concat!(
333 "Returns a `",
334 stringify!($name),
335 "` containing `value`.",
336 )]
337 #[inline]
338 pub const fn new(value: $prim_int) -> Self {
339 Self(<$prim>::new(swap_endian!($endian value)))
340 }
341 }
342
343 unsafe_impl_check_bytes_noop!(for $name);
346
347 impl $name {
348 #[doc = concat!(
352 "See [`",
353 stringify!($prim),
354 "::compare_exchange`] for more information.",
355 )]
356 #[inline]
357 pub fn compare_exchange(
358 &self,
359 current: $prim_int,
360 new: $prim_int,
361 success: Ordering,
362 failure: Ordering,
363 ) -> Result<$prim_int, $prim_int> {
364 match self.0.compare_exchange(
365 swap_endian!($endian current),
366 swap_endian!($endian new),
367 success,
368 failure,
369 ) {
370 Ok(x) => Ok(swap_endian!($endian x)),
371 Err(x) => Err(swap_endian!($endian x)),
372 }
373 }
374
375 #[doc = concat!(
379 "See [`",
380 stringify!($prim),
381 "::compare_exchange_weak`] for more information.",
382 )]
383 #[inline]
384 pub fn compare_exchange_weak(
385 &self,
386 current: $prim_int,
387 new: $prim_int,
388 success: Ordering,
389 failure: Ordering,
390 ) -> Result<$prim_int, $prim_int> {
391 match self.0.compare_exchange_weak(
392 swap_endian!($endian current),
393 swap_endian!($endian new),
394 success,
395 failure,
396 ) {
397 Ok(x) => Ok(swap_endian!($endian x)),
398 Err(x) => Ok(swap_endian!($endian x)),
399 }
400 }
401
402 #[doc = concat!(
405 "Because addition is not an endian-agnostic operation, ",
406 "`fetch_add` is implemented in terms of [`",
407 stringify!($prim),
408 "::compare_exchange_weak`] on ",
409 opposite_endian_name!($endian),
410 "-endian targets. This may result in worse performance on ",
411 "those targets.",
412 )]
413 #[doc = concat!(
415 "See [`",
416 stringify!($prim),
417 "::fetch_add`] for more information.",
418 )]
419 #[inline]
420 pub fn fetch_add(
421 &self,
422 val: $prim_int,
423 order: Ordering,
424 ) -> $prim_int {
425 if_native_endian!(
426 $endian
427 self.0.fetch_add(val, order),
428 self.fetch_update_fast(
429 order,
430 fetch_ordering(order),
431 |x| x + val,
432 ),
433 )
434 }
435
436 #[doc = concat!(
439 "See [`",
440 stringify!($prim),
441 "::fetch_and`] for more information.",
442 )]
443 #[inline]
444 pub fn fetch_and(
445 &self,
446 val: $prim_int,
447 order: Ordering,
448 ) -> $prim_int {
449 let val = swap_endian!($endian val);
450 swap_endian!($endian self.0.fetch_and(val, order))
451 }
452
453 #[doc = concat!(
456 "Because maximum is not an endian-agnostic operation, ",
457 "`fetch_max` is implemented in terms of [`",
458 stringify!($prim),
459 "::compare_exchange_weak`] on ",
460 opposite_endian_name!($endian),
461 "-endian targets. This may result in worse performance on ",
462 "those targets.",
463 )]
464 #[doc = concat!(
466 "See [`",
467 stringify!($prim),
468 "::fetch_max`] for more information.",
469 )]
470 #[inline]
471 pub fn fetch_max(
472 &self,
473 val: $prim_int,
474 order: Ordering,
475 ) -> $prim_int {
476 if_native_endian!(
477 $endian
478 self.0.fetch_max(val, order),
479 self.fetch_update_fast(
480 order,
481 fetch_ordering(order),
482 |x| <$prim_int>::max(x, val),
483 ),
484 )
485 }
486
487 #[doc = concat!(
490 "Because minimum is not an endian-agnostic operation, ",
491 "`fetch_min` is implemented in terms of [`",
492 stringify!($prim),
493 "::compare_exchange_weak`] on ",
494 opposite_endian_name!($endian),
495 "-endian targets. This may result in worse performance on ",
496 "those targets.",
497 )]
498 #[doc = concat!(
500 "See [`",
501 stringify!($prim),
502 "::fetch_min`] for more information.",
503 )]
504 #[inline]
505 pub fn fetch_min(
506 &self,
507 val: $prim_int,
508 order: Ordering,
509 ) -> $prim_int {
510 if_native_endian!(
511 $endian
512 self.0.fetch_min(val, order),
513 self.fetch_update_fast(
514 order,
515 fetch_ordering(order),
516 |x| <$prim_int>::min(x, val),
517 ),
518 )
519 }
520
521 #[doc = concat!(
524 "See [`",
525 stringify!($prim),
526 "::fetch_nand`] for more information.",
527 )]
528 #[inline]
529 pub fn fetch_nand(
530 &self,
531 val: $prim_int,
532 order: Ordering,
533 ) -> $prim_int {
534 let val = swap_endian!($endian val);
535 swap_endian!($endian self.0.fetch_nand(val, order))
536 }
537
538 #[doc = concat!(
541 "See [`",
542 stringify!($prim),
543 "::fetch_or`] for more information.",
544 )]
545 #[inline]
546 pub fn fetch_or(
547 &self,
548 val: $prim_int,
549 order: Ordering,
550 ) -> $prim_int {
551 let val = swap_endian!($endian val);
552 swap_endian!($endian self.0.fetch_or(val, order))
553 }
554
555 #[doc = concat!(
558 "Because subtraction is not an endian-agnostic operation, ",
559 "`fetch_sub` is implemented in terms of [`",
560 stringify!($prim),
561 "::compare_exchange_weak`] on ",
562 opposite_endian_name!($endian),
563 "-endian targets. This may result in worse performance on ",
564 "those targets.",
565 )]
566 #[doc = concat!(
568 "See [`",
569 stringify!($prim),
570 "::fetch_sub`] for more information.",
571 )]
572 #[inline]
573 pub fn fetch_sub(
574 &self,
575 val: $prim_int,
576 order: Ordering,
577 ) -> $prim_int {
578 if_native_endian!(
579 $endian
580 self.0.fetch_sub(val, order),
581 self.fetch_update_fast(
582 order,
583 fetch_ordering(order),
584 |x| x - val,
585 ),
586 )
587 }
588
589 #[allow(dead_code)]
590 #[inline(always)]
591 fn fetch_update_fast<F: Fn($prim_int) -> $prim_int>(
592 &self,
593 set_order: Ordering,
594 fetch_order: Ordering,
595 f: F,
596 ) -> $prim_int {
597 let mut prev = swap_endian!($endian self.0.load(fetch_order));
598 loop {
599 let next = swap_endian!($endian f(prev));
600 match self.0.compare_exchange_weak(
601 prev,
602 next,
603 set_order,
604 fetch_order,
605 ) {
606 Ok(x) => break x,
607 Err(next_prev) => {
608 prev = swap_endian!($endian next_prev);
609 }
610 }
611 }
612 }
613
614 #[doc = concat!(
619 "See [`",
620 stringify!($prim),
621 "::fetch_update`] for more information.",
622 )]
623 #[inline]
624 pub fn fetch_update<F: FnMut($prim_int) -> Option<$prim_int>>(
625 &self,
626 set_order: Ordering,
627 fetch_order: Ordering,
628 mut f: F,
629 ) -> Result<$prim_int, $prim_int> {
630 self.0.fetch_update(set_order, fetch_order, |x| {
631 f(swap_endian!($endian x)).map(|y| swap_endian!($endian y))
632 })
633 }
634
635 #[doc = concat!(
638 "See [`",
639 stringify!($prim),
640 "::fetch_xor`] for more information.",
641 )]
642 #[inline]
643 pub fn fetch_xor(
644 &self,
645 val: $prim_int,
646 order: Ordering,
647 ) -> $prim_int {
648 let val = swap_endian!($endian val);
649 swap_endian!($endian self.0.fetch_xor(val, order))
650 }
651
652 #[doc = concat!(
655 "See [`",
656 stringify!($prim),
657 "::into_inner`] for more information.",
658 )]
659 #[inline]
660 pub fn into_inner(self) -> $prim_int {
661 swap_endian!($endian self.0.into_inner())
662 }
663
664 #[doc = concat!(
667 "See [`",
668 stringify!($prim),
669 "::load`] for more information.",
670 )]
671 #[inline]
672 pub fn load(&self, order: Ordering) -> $prim_int {
673 swap_endian!($endian self.0.load(order))
674 }
675
676 #[doc = concat!(
679 "See [`",
680 stringify!($prim),
681 "::store`] for more information.",
682 )]
683 #[inline]
684 pub fn store(&self, val: $prim_int, order: Ordering) {
685 self.0.store(swap_endian!($endian val), order);
686 }
687
688 #[doc = concat!(
692 "See [`",
693 stringify!($prim),
694 "::swap`] for more information.",
695 )]
696 #[inline]
697 pub fn swap(&self, val: $prim_int, order: Ordering) -> $prim_int {
698 let val = swap_endian!($endian val);
699 swap_endian!($endian self.0.swap(val, order))
700 }
701 }
702
703 impl core::fmt::Debug for $name {
704 #[inline]
705 fn fmt(
706 &self,
707 f: &mut core::fmt::Formatter<'_>,
708 ) -> core::fmt::Result {
709 swap_endian!($endian self.load(Ordering::Relaxed)).fmt(f)
710 }
711 }
712
713 impl Default for $name {
714 #[inline]
715 fn default() -> Self {
716 Self::new(<$prim_int>::default())
717 }
718 }
719
720 impl From<$prim_int> for $name {
721 #[inline]
722 fn from(value: $prim_int) -> Self {
723 Self::new(value)
724 }
725 }
726 }
727}
728
729#[cfg(any(
730 target_has_atomic = "16",
731 target_has_atomic = "32",
732 target_has_atomic = "64",
733))]
734macro_rules! define_atomics {
735 ($(
736 $le:ident $be:ident:
737 $size_align:literal $prim:ty as $prim_int:ty
738 ),* $(,)?) => {
739 $(
740 define_atomic!($le: little $size_align $prim as $prim_int);
741 define_atomic!($be: big $size_align $prim as $prim_int);
742 )*
743 }
744}
745
746#[cfg(target_has_atomic = "16")]
747define_atomics! {
748 AtomicI16_le AtomicI16_be: 2 AtomicI16 as i16,
749 AtomicU16_le AtomicU16_be: 2 AtomicU16 as u16,
750}
751
752#[cfg(target_has_atomic = "32")]
753define_atomics! {
754 AtomicI32_le AtomicI32_be: 4 AtomicI32 as i32,
755 AtomicU32_le AtomicU32_be: 4 AtomicU32 as u32,
756}
757
758#[cfg(target_has_atomic = "64")]
759define_atomics! {
760 AtomicI64_le AtomicI64_be: 8 AtomicI64 as i64,
761 AtomicU64_le AtomicU64_be: 8 AtomicU64 as u64,
762}
763
764#[cfg(test)]
765mod tests {
766 use core::mem::transmute;
767
768 use super::*;
769
770 #[test]
771 fn signed_integers() {
772 assert_size_align! {
773 i16_be 2 2,
774 i16_le 2 2,
775 i32_be 4 4,
776 i32_le 4 4,
777 i64_be 8 8,
778 i64_le 8 8,
779 i128_be 16 16,
780 i128_le 16 16,
781 }
782
783 unsafe {
784 assert_eq!(
786 [0x02, 0x01],
787 transmute::<_, [u8; 2]>(i16_le::from_native(0x0102)),
788 );
789 assert_eq!(
790 [0x01, 0x02],
791 transmute::<_, [u8; 2]>(i16_be::from_native(0x0102)),
792 );
793
794 assert_eq!(
796 [0x04, 0x03, 0x02, 0x01],
797 transmute::<_, [u8; 4]>(i32_le::from_native(0x01020304)),
798 );
799 assert_eq!(
800 [0x01, 0x02, 0x03, 0x04],
801 transmute::<_, [u8; 4]>(i32_be::from_native(0x01020304)),
802 );
803
804 assert_eq!(
806 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
807 transmute::<_, [u8; 8]>(i64_le::from_native(
808 0x0102030405060708
809 )),
810 );
811 assert_eq!(
812 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
813 transmute::<_, [u8; 8]>(i64_be::from_native(
814 0x0102030405060708
815 )),
816 );
817
818 assert_eq!(
820 [
821 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
822 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
823 ],
824 transmute::<_, [u8; 16]>(i128_le::from_native(
825 0x0102030405060708090a0b0c0d0e0f10
826 )),
827 );
828 assert_eq!(
829 [
830 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
831 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
832 ],
833 transmute::<_, [u8; 16]>(i128_be::from_native(
834 0x0102030405060708090a0b0c0d0e0f10
835 )),
836 );
837 }
838 }
839
840 #[test]
841 fn unsigned_integers() {
842 assert_size_align! {
843 u16_be 2 2,
844 u16_le 2 2,
845 u32_be 4 4,
846 u32_le 4 4,
847 u64_be 8 8,
848 u64_le 8 8,
849 u128_be 16 16,
850 u128_le 16 16,
851 }
852
853 unsafe {
854 assert_eq!(
856 [0x02, 0x01],
857 transmute::<_, [u8; 2]>(u16_le::from_native(0x0102)),
858 );
859 assert_eq!(
860 [0x01, 0x02],
861 transmute::<_, [u8; 2]>(u16_be::from_native(0x0102)),
862 );
863
864 assert_eq!(
866 [0x04, 0x03, 0x02, 0x01],
867 transmute::<_, [u8; 4]>(u32_le::from_native(0x01020304)),
868 );
869 assert_eq!(
870 [0x01, 0x02, 0x03, 0x04],
871 transmute::<_, [u8; 4]>(u32_be::from_native(0x01020304)),
872 );
873
874 assert_eq!(
876 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
877 transmute::<_, [u8; 8]>(u64_le::from_native(
878 0x0102030405060708
879 )),
880 );
881 assert_eq!(
882 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
883 transmute::<_, [u8; 8]>(u64_be::from_native(
884 0x0102030405060708
885 )),
886 );
887
888 assert_eq!(
890 [
891 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
892 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
893 ],
894 transmute::<_, [u8; 16]>(u128_le::from_native(
895 0x0102030405060708090a0b0c0d0e0f10
896 )),
897 );
898 assert_eq!(
899 [
900 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
901 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
902 ],
903 transmute::<_, [u8; 16]>(u128_be::from_native(
904 0x0102030405060708090a0b0c0d0e0f10
905 )),
906 );
907 }
908 }
909
910 #[test]
911 fn floats() {
912 assert_size_align! {
913 f32_be 4 4,
914 f32_le 4 4,
915 f64_be 8 8,
916 f64_le 8 8,
917 }
918
919 unsafe {
920 assert_eq!(
922 [0xdb, 0x0f, 0x49, 0x40],
923 transmute::<_, [u8; 4]>(f32_le::from_native(
924 core::f32::consts::PI
925 )),
926 );
927 assert_eq!(
928 [0x40, 0x49, 0x0f, 0xdb],
929 transmute::<_, [u8; 4]>(f32_be::from_native(
930 core::f32::consts::PI
931 )),
932 );
933
934 assert_eq!(
936 [0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
937 transmute::<_, [u8; 8]>(f64_le::from_native(
938 core::f64::consts::PI
939 )),
940 );
941 assert_eq!(
942 [0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18],
943 transmute::<_, [u8; 8]>(f64_be::from_native(
944 core::f64::consts::PI
945 )),
946 );
947
948 assert_eq!(
950 [0x89, 0xf3, 0x01, 0x00],
951 transmute::<_, [u8; 4]>(char_le::from_native('🎉')),
952 );
953 assert_eq!(
954 [0x00, 0x01, 0xf3, 0x89],
955 transmute::<_, [u8; 4]>(char_be::from_native('🎉')),
956 );
957 }
958 }
959
960 #[test]
961 fn signed_non_zero() {
962 assert_size_align! {
963 NonZeroI16_le 2 2,
964 NonZeroI16_be 2 2,
965 NonZeroI32_le 4 4,
966 NonZeroI32_be 4 4,
967 NonZeroI64_le 8 8,
968 NonZeroI64_be 8 8,
969 NonZeroI128_le 16 16,
970 NonZeroI128_be 16 16,
971 }
972
973 unsafe {
974 assert_eq!(
976 [0x02, 0x01],
977 transmute::<_, [u8; 2]>(NonZeroI16_le::new_unchecked(0x0102)),
978 );
979 assert_eq!(
980 [0x01, 0x02],
981 transmute::<_, [u8; 2]>(NonZeroI16_be::new_unchecked(0x0102)),
982 );
983
984 assert_eq!(
986 [0x04, 0x03, 0x02, 0x01],
987 transmute::<_, [u8; 4]>(NonZeroI32_le::new_unchecked(
988 0x01020304
989 )),
990 );
991 assert_eq!(
992 [0x01, 0x02, 0x03, 0x04],
993 transmute::<_, [u8; 4]>(NonZeroI32_be::new_unchecked(
994 0x01020304
995 )),
996 );
997
998 assert_eq!(
1000 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1001 transmute::<_, [u8; 8]>(NonZeroI64_le::new_unchecked(
1002 0x0102030405060708
1003 )),
1004 );
1005 assert_eq!(
1006 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1007 transmute::<_, [u8; 8]>(NonZeroI64_be::new_unchecked(
1008 0x0102030405060708
1009 )),
1010 );
1011
1012 assert_eq!(
1014 [
1015 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1016 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
1017 ],
1018 transmute::<_, [u8; 16]>(NonZeroI128_le::new_unchecked(
1019 0x0102030405060708090a0b0c0d0e0f10
1020 )),
1021 );
1022 assert_eq!(
1023 [
1024 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
1025 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
1026 ],
1027 transmute::<_, [u8; 16]>(NonZeroI128_be::new_unchecked(
1028 0x0102030405060708090a0b0c0d0e0f10
1029 )),
1030 );
1031 }
1032 }
1033
1034 #[test]
1035 fn unsigned_non_zero() {
1036 assert_size_align! {
1037 NonZeroU16_le 2 2,
1038 NonZeroU16_be 2 2,
1039 NonZeroU32_le 4 4,
1040 NonZeroU32_be 4 4,
1041 NonZeroU64_le 8 8,
1042 NonZeroU64_be 8 8,
1043 NonZeroU128_le 16 16,
1044 NonZeroU128_be 16 16,
1045 }
1046
1047 unsafe {
1048 assert_eq!(
1050 [0x02, 0x01],
1051 transmute::<_, [u8; 2]>(NonZeroU16_le::new_unchecked(0x0102)),
1052 );
1053 assert_eq!(
1054 [0x01, 0x02],
1055 transmute::<_, [u8; 2]>(NonZeroU16_be::new_unchecked(0x0102)),
1056 );
1057
1058 assert_eq!(
1060 [0x04, 0x03, 0x02, 0x01],
1061 transmute::<_, [u8; 4]>(NonZeroU32_le::new_unchecked(
1062 0x01020304
1063 )),
1064 );
1065 assert_eq!(
1066 [0x01, 0x02, 0x03, 0x04],
1067 transmute::<_, [u8; 4]>(NonZeroU32_be::new_unchecked(
1068 0x01020304
1069 )),
1070 );
1071
1072 assert_eq!(
1074 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1075 transmute::<_, [u8; 8]>(NonZeroU64_le::new_unchecked(
1076 0x0102030405060708
1077 )),
1078 );
1079 assert_eq!(
1080 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1081 transmute::<_, [u8; 8]>(NonZeroU64_be::new_unchecked(
1082 0x0102030405060708
1083 )),
1084 );
1085
1086 assert_eq!(
1088 [
1089 0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
1090 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
1091 ],
1092 transmute::<_, [u8; 16]>(NonZeroU128_le::new_unchecked(
1093 0x0102030405060708090a0b0c0d0e0f10
1094 )),
1095 );
1096 assert_eq!(
1097 [
1098 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
1099 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
1100 ],
1101 transmute::<_, [u8; 16]>(NonZeroU128_be::new_unchecked(
1102 0x0102030405060708090a0b0c0d0e0f10
1103 )),
1104 );
1105 }
1106 }
1107
1108 #[cfg(feature = "bytecheck")]
1109 #[test]
1110 fn unaligned_non_zero() {
1111 use bytecheck::{
1112 rancor::{Failure, Strategy},
1113 CheckBytes,
1114 };
1115 use unaligned::{u32_ule, NonZeroU32_ule};
1116
1117 let zero = u32_ule::from_native(0);
1118 let ptr = (&zero as *const u32_ule).cast::<NonZeroU32_ule>();
1119 let mut unit = ();
1120 let context = Strategy::<_, Failure>::wrap(&mut unit);
1121 unsafe {
1122 <NonZeroU32_ule as CheckBytes<Strategy<(), Failure>>>::check_bytes(
1123 ptr, context,
1124 )
1125 .unwrap_err();
1126 }
1127 }
1128
1129 #[cfg(target_has_atomic = "16")]
1130 #[test]
1131 fn atomics_16() {
1132 assert_size_align! {
1133 AtomicI16_le 2 2,
1134 AtomicI16_be 2 2,
1135 AtomicU16_le 2 2,
1136 AtomicU16_be 2 2,
1137 }
1138
1139 unsafe {
1140 assert_eq!(
1142 [0x02, 0x01],
1143 transmute::<_, [u8; 2]>(AtomicI16_le::new(0x0102)),
1144 );
1145 assert_eq!(
1146 [0x01, 0x02],
1147 transmute::<_, [u8; 2]>(AtomicI16_be::new(0x0102)),
1148 );
1149
1150 assert_eq!(
1152 [0x02, 0x01],
1153 transmute::<_, [u8; 2]>(AtomicU16_le::new(0x0102)),
1154 );
1155 assert_eq!(
1156 [0x01, 0x02],
1157 transmute::<_, [u8; 2]>(AtomicU16_be::new(0x0102)),
1158 );
1159 }
1160 }
1161
1162 #[cfg(target_has_atomic = "32")]
1163 #[test]
1164 fn atomics_32() {
1165 assert_size_align! {
1166 AtomicI32_le 4 4,
1167 AtomicI32_be 4 4,
1168 AtomicU32_le 4 4,
1169 AtomicU32_be 4 4,
1170 }
1171
1172 unsafe {
1173 assert_eq!(
1175 [0x04, 0x03, 0x02, 0x01],
1176 transmute::<_, [u8; 4]>(AtomicI32_le::new(0x01020304)),
1177 );
1178 assert_eq!(
1179 [0x01, 0x02, 0x03, 0x04],
1180 transmute::<_, [u8; 4]>(AtomicI32_be::new(0x01020304)),
1181 );
1182
1183 assert_eq!(
1185 [0x04, 0x03, 0x02, 0x01],
1186 transmute::<_, [u8; 4]>(AtomicU32_le::new(0x01020304)),
1187 );
1188 assert_eq!(
1189 [0x01, 0x02, 0x03, 0x04],
1190 transmute::<_, [u8; 4]>(AtomicU32_be::new(0x01020304)),
1191 );
1192 }
1193 }
1194
1195 #[cfg(target_has_atomic = "64")]
1196 #[test]
1197 fn atomics_64() {
1198 assert_size_align! {
1199 AtomicI64_le 8 8,
1200 AtomicI64_be 8 8,
1201 AtomicU64_le 8 8,
1202 AtomicU64_be 8 8,
1203 }
1204
1205 unsafe {
1206 assert_eq!(
1208 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1209 transmute::<_, [u8; 8]>(AtomicI64_le::new(0x0102030405060708)),
1210 );
1211 assert_eq!(
1212 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1213 transmute::<_, [u8; 8]>(AtomicI64_be::new(0x0102030405060708)),
1214 );
1215
1216 assert_eq!(
1218 [0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
1219 transmute::<_, [u8; 8]>(AtomicU64_le::new(0x0102030405060708)),
1220 );
1221 assert_eq!(
1222 [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
1223 transmute::<_, [u8; 8]>(AtomicU64_be::new(0x0102030405060708)),
1224 );
1225 }
1226 }
1227}