#![doc = include_str!("../example.md")]
#![no_std]
#![deny(
future_incompatible,
missing_docs,
nonstandard_style,
unsafe_op_in_unsafe_fn,
unused,
warnings,
clippy::all,
clippy::missing_safety_doc,
clippy::undocumented_unsafe_blocks,
rustdoc::broken_intra_doc_links,
rustdoc::missing_crate_level_docs
)]
#![cfg_attr(all(docsrs, not(doctest)), feature(doc_cfg, doc_auto_cfg))]
#[macro_use]
mod common;
#[cfg(feature = "bytecheck")]
mod context;
#[macro_use]
mod traits;
#[macro_use]
mod util;
pub mod unaligned;
#[cfg(target_has_atomic = "16")]
use core::sync::atomic::{AtomicI16, AtomicU16};
#[cfg(target_has_atomic = "32")]
use core::sync::atomic::{AtomicI32, AtomicU32};
#[cfg(target_has_atomic = "64")]
use core::sync::atomic::{AtomicI64, AtomicU64};
use core::{
num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64,
},
sync::atomic::Ordering,
};
#[rustfmt::skip]
macro_rules! define_newtype {
(
$(#[$attr:meta])*
$name:ident: $endian:ident $size_align:literal $prim:ty
) => {
#[allow(non_camel_case_types)]
#[doc = concat!(
"A ",
endian_name!($endian),
"-endian `",
stringify!($prim),
"` with a guaranteed size and alignment of `",
stringify!($size_align),
"`.",
)]
$(#[$attr])*
#[repr(C, align($size_align))]
pub struct $name($prim);
};
}
macro_rules! define_signed_integer {
($name:ident: $endian:ident $size_align:literal $prim:ident) => {
define_newtype!(
#[cfg_attr(
feature = "zerocopy-0_8",
derive(
zerocopy_derive::FromBytes,
zerocopy_derive::IntoBytes,
zerocopy_derive::Immutable,
zerocopy_derive::KnownLayout,
),
)]
$name: $endian $size_align $prim
);
impl_integer!($name: $endian $prim);
impl_signed_integer_traits!($name: $endian $prim);
};
}
macro_rules! define_signed_integers {
($($le:ident $be:ident: $size_align:literal $prim:ident),* $(,)?) => {
$(
define_signed_integer!($le: little $size_align $prim);
define_signed_integer!($be: big $size_align $prim);
)*
};
}
define_signed_integers! {
i16_le i16_be: 2 i16,
i32_le i32_be: 4 i32,
i64_le i64_be: 8 i64,
i128_le i128_be: 16 i128,
}
macro_rules! define_unsigned_integer {
($name:ident: $endian:ident $size_align:literal $prim:ident) => {
define_newtype!(
#[cfg_attr(
feature = "zerocopy-0_8",
derive(
zerocopy_derive::FromBytes,
zerocopy_derive::IntoBytes,
zerocopy_derive::Immutable,
zerocopy_derive::KnownLayout,
),
)]
$name: $endian $size_align $prim
);
impl_integer!($name: $endian $prim);
impl_unsigned_integer_traits!($name: $endian $prim);
}
}
macro_rules! define_unsigned_integers {
($($le:ident $be:ident: $size_align:literal $prim:ident),* $(,)?) => {
$(
define_unsigned_integer!($le: little $size_align $prim);
define_unsigned_integer!($be: big $size_align $prim);
)*
};
}
define_unsigned_integers! {
u16_le u16_be: 2 u16,
u32_le u32_be: 4 u32,
u64_le u64_be: 8 u64,
u128_le u128_be: 16 u128,
}
macro_rules! define_float {
(
$name:ident:
$endian:ident $size_align:literal $prim:ty as $prim_int:ty
) => {
define_newtype!(
#[cfg_attr(
feature = "zerocopy-0_8",
derive(
zerocopy_derive::FromBytes,
zerocopy_derive::IntoBytes,
zerocopy_derive::Immutable,
zerocopy_derive::KnownLayout,
),
)]
$name: $endian $size_align $prim
);
impl_float!($name: $endian $prim as $prim_int);
};
}
macro_rules! define_floats {
($(
$le:ident $be:ident:
$size_align:literal $prim:ty as $prim_int:ty
),* $(,)?) => {
$(
define_float!($le: little $size_align $prim as $prim_int);
define_float!($be: big $size_align $prim as $prim_int);
)*
};
}
define_floats! {
f32_le f32_be: 4 f32 as u32,
f64_le f64_be: 8 f64 as u64,
}
macro_rules! define_char {
($name:ident: $endian:ident) => {
define_newtype!(
#[cfg_attr(
feature = "zerocopy-0_8",
derive(
zerocopy_derive::IntoBytes,
zerocopy_derive::Immutable,
zerocopy_derive::KnownLayout,
),
)]
$name: $endian 4 u32
);
impl_char!($name: $endian);
};
}
define_char!(char_le: little);
define_char!(char_be: big);
macro_rules! define_nonzero {
(
$name:ident:
$endian:ident $size_align:literal $prim:ty as $prim_int:ty
) => {
define_newtype!(
#[cfg_attr(
feature = "zerocopy-0_8",
derive(
zerocopy_derive::TryFromBytes,
zerocopy_derive::IntoBytes,
zerocopy_derive::Immutable,
zerocopy_derive::KnownLayout,
),
)]
$name: $endian $size_align $prim
);
impl_nonzero!($name: $endian $prim as $prim_int);
#[cfg(feature = "bytecheck")]
unsafe impl<C> bytecheck::CheckBytes<C> for $name
where
C: bytecheck::rancor::Fallible + ?Sized,
C::Error: bytecheck::rancor::Trace,
$prim: bytecheck::CheckBytes<C>,
{
#[inline]
unsafe fn check_bytes(
value: *const Self,
context: &mut C,
) -> Result<(), C::Error> {
use bytecheck::rancor::ResultExt as _;
unsafe {
<$prim>::check_bytes(value.cast(), context)
.with_trace(|| $crate::context::ValueCheckContext {
inner_name: core::stringify!($prim),
outer_name: core::stringify!($name),
})
}
}
}
};
}
macro_rules! define_nonzeros {
($(
$le:ident $be:ident:
$size_align:literal $prim:ty as $prim_int:ty
),* $(,)?) => {
$(
define_nonzero!($le: little $size_align $prim as $prim_int);
define_nonzero!($be: big $size_align $prim as $prim_int);
)*
}
}
define_nonzeros! {
NonZeroI16_le NonZeroI16_be: 2 NonZeroI16 as i16,
NonZeroI32_le NonZeroI32_be: 4 NonZeroI32 as i32,
NonZeroI64_le NonZeroI64_be: 8 NonZeroI64 as i64,
NonZeroI128_le NonZeroI128_be: 16 NonZeroI128 as i128,
NonZeroU16_le NonZeroU16_be: 2 NonZeroU16 as u16,
NonZeroU32_le NonZeroU32_be: 4 NonZeroU32 as u32,
NonZeroU64_le NonZeroU64_be: 8 NonZeroU64 as u64,
NonZeroU128_le NonZeroU128_be: 16 NonZeroU128 as u128,
}
#[allow(dead_code)]
const fn fetch_ordering(order: Ordering) -> Ordering {
match order {
Ordering::Relaxed => Ordering::Relaxed,
Ordering::Release => Ordering::Relaxed,
Ordering::Acquire => Ordering::Acquire,
Ordering::AcqRel => Ordering::Acquire,
Ordering::SeqCst => Ordering::SeqCst,
order => order,
}
}
#[cfg(any(
target_has_atomic = "16",
target_has_atomic = "32",
target_has_atomic = "64",
))]
macro_rules! define_atomic {
(
$name:ident:
$endian:ident $size_align:literal $prim:ty as $prim_int:ty
) => {
define_newtype!(
#[cfg_attr(
feature = "zerocopy-0_8",
derive(
zerocopy_derive::FromBytes,
zerocopy_derive::IntoBytes,
zerocopy_derive::KnownLayout,
),
)]
$name: $endian $size_align $prim
);
impl $name {
#[doc = concat!(
"Returns a `",
stringify!($name),
"` containing `value`.",
)]
#[inline]
pub const fn new(value: $prim_int) -> Self {
Self(<$prim>::new(swap_endian!($endian value)))
}
}
unsafe_impl_check_bytes_noop!(for $name);
impl $name {
#[doc = concat!(
"See [`",
stringify!($prim),
"::compare_exchange`] for more information.",
)]
#[inline]
pub fn compare_exchange(
&self,
current: $prim_int,
new: $prim_int,
success: Ordering,
failure: Ordering,
) -> Result<$prim_int, $prim_int> {
match self.0.compare_exchange(
swap_endian!($endian current),
swap_endian!($endian new),
success,
failure,
) {
Ok(x) => Ok(swap_endian!($endian x)),
Err(x) => Err(swap_endian!($endian x)),
}
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::compare_exchange_weak`] for more information.",
)]
#[inline]
pub fn compare_exchange_weak(
&self,
current: $prim_int,
new: $prim_int,
success: Ordering,
failure: Ordering,
) -> Result<$prim_int, $prim_int> {
match self.0.compare_exchange_weak(
swap_endian!($endian current),
swap_endian!($endian new),
success,
failure,
) {
Ok(x) => Ok(swap_endian!($endian x)),
Err(x) => Ok(swap_endian!($endian x)),
}
}
#[doc = concat!(
"Because addition is not an endian-agnostic operation, ",
"`fetch_add` is implemented in terms of [`",
stringify!($prim),
"::compare_exchange_weak`] on ",
opposite_endian_name!($endian),
"-endian targets. This may result in worse performance on ",
"those targets.",
)]
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_add`] for more information.",
)]
#[inline]
pub fn fetch_add(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
if_native_endian!(
$endian
self.0.fetch_add(val, order),
self.fetch_update_fast(
order,
fetch_ordering(order),
|x| x + val,
),
)
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_and`] for more information.",
)]
#[inline]
pub fn fetch_and(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
let val = swap_endian!($endian val);
swap_endian!($endian self.0.fetch_and(val, order))
}
#[doc = concat!(
"Because maximum is not an endian-agnostic operation, ",
"`fetch_max` is implemented in terms of [`",
stringify!($prim),
"::compare_exchange_weak`] on ",
opposite_endian_name!($endian),
"-endian targets. This may result in worse performance on ",
"those targets.",
)]
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_max`] for more information.",
)]
#[inline]
pub fn fetch_max(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
if_native_endian!(
$endian
self.0.fetch_max(val, order),
self.fetch_update_fast(
order,
fetch_ordering(order),
|x| <$prim_int>::max(x, val),
),
)
}
#[doc = concat!(
"Because minimum is not an endian-agnostic operation, ",
"`fetch_min` is implemented in terms of [`",
stringify!($prim),
"::compare_exchange_weak`] on ",
opposite_endian_name!($endian),
"-endian targets. This may result in worse performance on ",
"those targets.",
)]
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_min`] for more information.",
)]
#[inline]
pub fn fetch_min(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
if_native_endian!(
$endian
self.0.fetch_min(val, order),
self.fetch_update_fast(
order,
fetch_ordering(order),
|x| <$prim_int>::min(x, val),
),
)
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_nand`] for more information.",
)]
#[inline]
pub fn fetch_nand(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
let val = swap_endian!($endian val);
swap_endian!($endian self.0.fetch_nand(val, order))
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_or`] for more information.",
)]
#[inline]
pub fn fetch_or(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
let val = swap_endian!($endian val);
swap_endian!($endian self.0.fetch_or(val, order))
}
#[doc = concat!(
"Because subtraction is not an endian-agnostic operation, ",
"`fetch_sub` is implemented in terms of [`",
stringify!($prim),
"::compare_exchange_weak`] on ",
opposite_endian_name!($endian),
"-endian targets. This may result in worse performance on ",
"those targets.",
)]
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_sub`] for more information.",
)]
#[inline]
pub fn fetch_sub(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
if_native_endian!(
$endian
self.0.fetch_sub(val, order),
self.fetch_update_fast(
order,
fetch_ordering(order),
|x| x - val,
),
)
}
#[allow(dead_code)]
#[inline(always)]
fn fetch_update_fast<F: Fn($prim_int) -> $prim_int>(
&self,
set_order: Ordering,
fetch_order: Ordering,
f: F,
) -> $prim_int {
let mut prev = swap_endian!($endian self.0.load(fetch_order));
loop {
let next = swap_endian!($endian f(prev));
match self.0.compare_exchange_weak(
prev,
next,
set_order,
fetch_order,
) {
Ok(x) => break x,
Err(next_prev) => {
prev = swap_endian!($endian next_prev);
}
}
}
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_update`] for more information.",
)]
#[inline]
pub fn fetch_update<F: FnMut($prim_int) -> Option<$prim_int>>(
&self,
set_order: Ordering,
fetch_order: Ordering,
mut f: F,
) -> Result<$prim_int, $prim_int> {
self.0.fetch_update(set_order, fetch_order, |x| {
f(swap_endian!($endian x)).map(|y| swap_endian!($endian y))
})
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::fetch_xor`] for more information.",
)]
#[inline]
pub fn fetch_xor(
&self,
val: $prim_int,
order: Ordering,
) -> $prim_int {
let val = swap_endian!($endian val);
swap_endian!($endian self.0.fetch_xor(val, order))
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::into_inner`] for more information.",
)]
#[inline]
pub fn into_inner(self) -> $prim_int {
swap_endian!($endian self.0.into_inner())
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::load`] for more information.",
)]
#[inline]
pub fn load(&self, order: Ordering) -> $prim_int {
swap_endian!($endian self.0.load(order))
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::store`] for more information.",
)]
#[inline]
pub fn store(&self, val: $prim_int, order: Ordering) {
self.0.store(swap_endian!($endian val), order);
}
#[doc = concat!(
"See [`",
stringify!($prim),
"::swap`] for more information.",
)]
#[inline]
pub fn swap(&self, val: $prim_int, order: Ordering) -> $prim_int {
let val = swap_endian!($endian val);
swap_endian!($endian self.0.swap(val, order))
}
}
impl core::fmt::Debug for $name {
#[inline]
fn fmt(
&self,
f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result {
swap_endian!($endian self.load(Ordering::Relaxed)).fmt(f)
}
}
impl Default for $name {
#[inline]
fn default() -> Self {
Self::new(<$prim_int>::default())
}
}
impl From<$prim_int> for $name {
#[inline]
fn from(value: $prim_int) -> Self {
Self::new(value)
}
}
}
}
#[cfg(any(
target_has_atomic = "16",
target_has_atomic = "32",
target_has_atomic = "64",
))]
macro_rules! define_atomics {
($(
$le:ident $be:ident:
$size_align:literal $prim:ty as $prim_int:ty
),* $(,)?) => {
$(
define_atomic!($le: little $size_align $prim as $prim_int);
define_atomic!($be: big $size_align $prim as $prim_int);
)*
}
}
#[cfg(target_has_atomic = "16")]
define_atomics! {
AtomicI16_le AtomicI16_be: 2 AtomicI16 as i16,
AtomicU16_le AtomicU16_be: 2 AtomicU16 as u16,
}
#[cfg(target_has_atomic = "32")]
define_atomics! {
AtomicI32_le AtomicI32_be: 4 AtomicI32 as i32,
AtomicU32_le AtomicU32_be: 4 AtomicU32 as u32,
}
#[cfg(target_has_atomic = "64")]
define_atomics! {
AtomicI64_le AtomicI64_be: 8 AtomicI64 as i64,
AtomicU64_le AtomicU64_be: 8 AtomicU64 as u64,
}
#[cfg(test)]
mod tests {
use core::mem::transmute;
use super::*;
#[test]
fn signed_integers() {
assert_size_align! {
i16_be 2 2,
i16_le 2 2,
i32_be 4 4,
i32_le 4 4,
i64_be 8 8,
i64_le 8 8,
i128_be 16 16,
i128_le 16 16,
}
unsafe {
assert_eq!(
[0x02, 0x01],
transmute::<_, [u8; 2]>(i16_le::from_native(0x0102)),
);
assert_eq!(
[0x01, 0x02],
transmute::<_, [u8; 2]>(i16_be::from_native(0x0102)),
);
assert_eq!(
[0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 4]>(i32_le::from_native(0x01020304)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04],
transmute::<_, [u8; 4]>(i32_be::from_native(0x01020304)),
);
assert_eq!(
[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 8]>(i64_le::from_native(
0x0102030405060708
)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
transmute::<_, [u8; 8]>(i64_be::from_native(
0x0102030405060708
)),
);
assert_eq!(
[
0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
0x06, 0x05, 0x04, 0x03, 0x02, 0x01
],
transmute::<_, [u8; 16]>(i128_le::from_native(
0x0102030405060708090a0b0c0d0e0f10
)),
);
assert_eq!(
[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
],
transmute::<_, [u8; 16]>(i128_be::from_native(
0x0102030405060708090a0b0c0d0e0f10
)),
);
}
}
#[test]
fn unsigned_integers() {
assert_size_align! {
u16_be 2 2,
u16_le 2 2,
u32_be 4 4,
u32_le 4 4,
u64_be 8 8,
u64_le 8 8,
u128_be 16 16,
u128_le 16 16,
}
unsafe {
assert_eq!(
[0x02, 0x01],
transmute::<_, [u8; 2]>(u16_le::from_native(0x0102)),
);
assert_eq!(
[0x01, 0x02],
transmute::<_, [u8; 2]>(u16_be::from_native(0x0102)),
);
assert_eq!(
[0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 4]>(u32_le::from_native(0x01020304)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04],
transmute::<_, [u8; 4]>(u32_be::from_native(0x01020304)),
);
assert_eq!(
[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 8]>(u64_le::from_native(
0x0102030405060708
)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
transmute::<_, [u8; 8]>(u64_be::from_native(
0x0102030405060708
)),
);
assert_eq!(
[
0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
0x06, 0x05, 0x04, 0x03, 0x02, 0x01
],
transmute::<_, [u8; 16]>(u128_le::from_native(
0x0102030405060708090a0b0c0d0e0f10
)),
);
assert_eq!(
[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
],
transmute::<_, [u8; 16]>(u128_be::from_native(
0x0102030405060708090a0b0c0d0e0f10
)),
);
}
}
#[test]
fn floats() {
assert_size_align! {
f32_be 4 4,
f32_le 4 4,
f64_be 8 8,
f64_le 8 8,
}
unsafe {
assert_eq!(
[0xdb, 0x0f, 0x49, 0x40],
transmute::<_, [u8; 4]>(f32_le::from_native(
core::f32::consts::PI
)),
);
assert_eq!(
[0x40, 0x49, 0x0f, 0xdb],
transmute::<_, [u8; 4]>(f32_be::from_native(
core::f32::consts::PI
)),
);
assert_eq!(
[0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40],
transmute::<_, [u8; 8]>(f64_le::from_native(
core::f64::consts::PI
)),
);
assert_eq!(
[0x40, 0x09, 0x21, 0xfb, 0x54, 0x44, 0x2d, 0x18],
transmute::<_, [u8; 8]>(f64_be::from_native(
core::f64::consts::PI
)),
);
assert_eq!(
[0x89, 0xf3, 0x01, 0x00],
transmute::<_, [u8; 4]>(char_le::from_native('🎉')),
);
assert_eq!(
[0x00, 0x01, 0xf3, 0x89],
transmute::<_, [u8; 4]>(char_be::from_native('🎉')),
);
}
}
#[test]
fn signed_non_zero() {
assert_size_align! {
NonZeroI16_le 2 2,
NonZeroI16_be 2 2,
NonZeroI32_le 4 4,
NonZeroI32_be 4 4,
NonZeroI64_le 8 8,
NonZeroI64_be 8 8,
NonZeroI128_le 16 16,
NonZeroI128_be 16 16,
}
unsafe {
assert_eq!(
[0x02, 0x01],
transmute::<_, [u8; 2]>(NonZeroI16_le::new_unchecked(0x0102)),
);
assert_eq!(
[0x01, 0x02],
transmute::<_, [u8; 2]>(NonZeroI16_be::new_unchecked(0x0102)),
);
assert_eq!(
[0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 4]>(NonZeroI32_le::new_unchecked(
0x01020304
)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04],
transmute::<_, [u8; 4]>(NonZeroI32_be::new_unchecked(
0x01020304
)),
);
assert_eq!(
[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 8]>(NonZeroI64_le::new_unchecked(
0x0102030405060708
)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
transmute::<_, [u8; 8]>(NonZeroI64_be::new_unchecked(
0x0102030405060708
)),
);
assert_eq!(
[
0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
0x06, 0x05, 0x04, 0x03, 0x02, 0x01
],
transmute::<_, [u8; 16]>(NonZeroI128_le::new_unchecked(
0x0102030405060708090a0b0c0d0e0f10
)),
);
assert_eq!(
[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
],
transmute::<_, [u8; 16]>(NonZeroI128_be::new_unchecked(
0x0102030405060708090a0b0c0d0e0f10
)),
);
}
}
#[test]
fn unsigned_non_zero() {
assert_size_align! {
NonZeroU16_le 2 2,
NonZeroU16_be 2 2,
NonZeroU32_le 4 4,
NonZeroU32_be 4 4,
NonZeroU64_le 8 8,
NonZeroU64_be 8 8,
NonZeroU128_le 16 16,
NonZeroU128_be 16 16,
}
unsafe {
assert_eq!(
[0x02, 0x01],
transmute::<_, [u8; 2]>(NonZeroU16_le::new_unchecked(0x0102)),
);
assert_eq!(
[0x01, 0x02],
transmute::<_, [u8; 2]>(NonZeroU16_be::new_unchecked(0x0102)),
);
assert_eq!(
[0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 4]>(NonZeroU32_le::new_unchecked(
0x01020304
)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04],
transmute::<_, [u8; 4]>(NonZeroU32_be::new_unchecked(
0x01020304
)),
);
assert_eq!(
[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 8]>(NonZeroU64_le::new_unchecked(
0x0102030405060708
)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
transmute::<_, [u8; 8]>(NonZeroU64_be::new_unchecked(
0x0102030405060708
)),
);
assert_eq!(
[
0x10, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07,
0x06, 0x05, 0x04, 0x03, 0x02, 0x01
],
transmute::<_, [u8; 16]>(NonZeroU128_le::new_unchecked(
0x0102030405060708090a0b0c0d0e0f10
)),
);
assert_eq!(
[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10
],
transmute::<_, [u8; 16]>(NonZeroU128_be::new_unchecked(
0x0102030405060708090a0b0c0d0e0f10
)),
);
}
}
#[cfg(feature = "bytecheck")]
#[test]
fn unaligned_non_zero() {
use bytecheck::{
rancor::{Failure, Strategy},
CheckBytes,
};
use unaligned::{u32_ule, NonZeroU32_ule};
let zero = u32_ule::from_native(0);
let ptr = (&zero as *const u32_ule).cast::<NonZeroU32_ule>();
let mut unit = ();
let context = Strategy::<_, Failure>::wrap(&mut unit);
unsafe {
<NonZeroU32_ule as CheckBytes<Strategy<(), Failure>>>::check_bytes(
ptr, context,
)
.unwrap_err();
}
}
#[cfg(target_has_atomic = "16")]
#[test]
fn atomics_16() {
assert_size_align! {
AtomicI16_le 2 2,
AtomicI16_be 2 2,
AtomicU16_le 2 2,
AtomicU16_be 2 2,
}
unsafe {
assert_eq!(
[0x02, 0x01],
transmute::<_, [u8; 2]>(AtomicI16_le::new(0x0102)),
);
assert_eq!(
[0x01, 0x02],
transmute::<_, [u8; 2]>(AtomicI16_be::new(0x0102)),
);
assert_eq!(
[0x02, 0x01],
transmute::<_, [u8; 2]>(AtomicU16_le::new(0x0102)),
);
assert_eq!(
[0x01, 0x02],
transmute::<_, [u8; 2]>(AtomicU16_be::new(0x0102)),
);
}
}
#[cfg(target_has_atomic = "32")]
#[test]
fn atomics_32() {
assert_size_align! {
AtomicI32_le 4 4,
AtomicI32_be 4 4,
AtomicU32_le 4 4,
AtomicU32_be 4 4,
}
unsafe {
assert_eq!(
[0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 4]>(AtomicI32_le::new(0x01020304)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04],
transmute::<_, [u8; 4]>(AtomicI32_be::new(0x01020304)),
);
assert_eq!(
[0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 4]>(AtomicU32_le::new(0x01020304)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04],
transmute::<_, [u8; 4]>(AtomicU32_be::new(0x01020304)),
);
}
}
#[cfg(target_has_atomic = "64")]
#[test]
fn atomics_64() {
assert_size_align! {
AtomicI64_le 8 8,
AtomicI64_be 8 8,
AtomicU64_le 8 8,
AtomicU64_be 8 8,
}
unsafe {
assert_eq!(
[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 8]>(AtomicI64_le::new(0x0102030405060708)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
transmute::<_, [u8; 8]>(AtomicI64_be::new(0x0102030405060708)),
);
assert_eq!(
[0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01],
transmute::<_, [u8; 8]>(AtomicU64_le::new(0x0102030405060708)),
);
assert_eq!(
[0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
transmute::<_, [u8; 8]>(AtomicU64_be::new(0x0102030405060708)),
);
}
}
}