use core::{alloc::Layout, fmt, marker::PhantomData, mem, num::NonZero, ops, ptr};
pub const fn align<const N: usize>() -> Align<N>
where
Align<N>: Alignment,
{
Align::new()
}
pub const fn padding<const N: usize>() -> Padding<N>
where
Align<N>: Alignment,
{
Padding::new()
}
pub const fn aligned<T, const N: usize>(value: T) -> Aligned<T, N>
where
Align<N>: Alignment,
{
Aligned::new(value)
}
pub const fn misaligned<T: Unpadded, const N: usize>(value: T) -> Misaligned<T, N>
where
Align<N>: Alignment,
{
Misaligned::new(value)
}
#[cfg(target_pointer_width = "16")]
#[repr(usize)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
enum InnerAlignment {
#[default]
_A0 = 0x1,
_A1 = 0x2,
_A2 = 0x4,
_A3 = 0x8,
_A4 = 0x10,
_A5 = 0x20,
_A6 = 0x40,
_A7 = 0x80,
_A8 = 0x100,
_A9 = 0x200,
_A10 = 0x400,
_A11 = 0x800,
_A12 = 0x1000,
_A13 = 0x2000,
_A14 = 0x4000,
_A15 = 0x8000,
}
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
#[repr(usize)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
enum InnerAlignment {
#[default]
_A0 = 0x1,
_A1 = 0x2,
_A2 = 0x4,
_A3 = 0x8,
_A4 = 0x10,
_A5 = 0x20,
_A6 = 0x40,
_A7 = 0x80,
_A8 = 0x100,
_A9 = 0x200,
_A10 = 0x400,
_A11 = 0x800,
_A12 = 0x1000,
_A13 = 0x2000,
_A14 = 0x4000,
_A15 = 0x8000,
_A16 = 0x10000,
_A17 = 0x20000,
_A18 = 0x40000,
_A19 = 0x80000,
_A20 = 0x100000,
_A21 = 0x200000,
_A22 = 0x400000,
_A23 = 0x800000,
_A24 = 0x1000000,
_A25 = 0x2000000,
_A26 = 0x4000000,
_A27 = 0x8000000,
_A28 = 0x10000000,
_A29 = 0x20000000,
}
impl InnerAlignment {
#[cfg(target_pointer_width = "16")]
const MAX: usize = 0x8000;
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
const MAX: usize = 0x20000000;
}
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct DynAlign(InnerAlignment);
impl DynAlign {
#[inline]
pub const fn of<T>() -> DynAlign {
unsafe { DynAlign::from_usize_unchecked(mem::align_of::<T>()) }
}
#[inline]
pub const fn of_val<T: ?Sized>(val: &T) -> DynAlign {
unsafe { DynAlign::from_usize_unchecked(mem::align_of_val::<T>(val)) }
}
#[inline]
pub const fn from_usize(value: usize) -> Option<DynAlign> {
if value.is_power_of_two() && value <= InnerAlignment::MAX {
Some(unsafe { DynAlign::from_usize_unchecked(value) })
} else {
None
}
}
#[inline]
pub const unsafe fn from_usize_unchecked(value: usize) -> DynAlign {
DynAlign(unsafe { mem::transmute::<usize, InnerAlignment>(value) })
}
#[inline]
pub const fn to_usize(self) -> usize {
self.0 as usize
}
#[inline]
pub const fn to_nonzero_usize(self) -> NonZero<usize> {
unsafe { NonZero::new_unchecked(self.to_usize()) }
}
#[inline]
pub const fn padding_layout(self) -> Layout {
unsafe { Layout::from_size_align_unchecked(self.to_usize(), self.to_usize()) }
}
#[inline]
pub const fn align_layout(self) -> Layout {
unsafe { Layout::from_size_align_unchecked(0, self.to_usize()) }
}
}
impl fmt::Debug for DynAlign {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let n = self.to_usize();
let mut buf = *b"1 << 63";
let len = if n < (1 << 10) {
buf[5] = b'0' + (n.trailing_zeros() as u8);
6
} else {
let exp = n.trailing_zeros() as u8;
buf[5] = b'0' + (exp / 10);
buf[6] = b'0' + (exp % 10);
7
};
let s = unsafe { str::from_utf8_unchecked(&buf[..len]) };
f.pad(s)
}
}
#[derive(Copy, Clone)]
pub struct Align<const N: usize>([<Self as Alignment>::Align; 0])
where
Align<N>: Alignment;
impl<const N: usize> Align<N>
where
Align<N>: Alignment,
{
#[inline]
pub const fn new() -> Align<N> {
Align([])
}
}
impl<const N: usize> fmt::Debug for Align<N>
where
Align<N>: Alignment,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (buf, len) = const {
let mut buf = *b"Align<{1 << 63}>";
let len = if N < (1 << 10) {
buf[12] = b'0' + (N.trailing_zeros() as u8);
buf[13] = b'}';
buf[14] = b'>';
15
} else {
let exp = N.trailing_zeros() as u8;
buf[12] = b'0' + (exp / 10);
buf[13] = b'0' + (exp % 10);
16
};
(buf, len)
};
let s = unsafe { str::from_utf8_unchecked(&buf[..len]) };
f.pad(s)
}
}
#[derive(Copy, Clone)]
pub struct Padding<const N: usize>(mem::MaybeUninit<<Align<N> as Alignment>::Padding>)
where
Align<N>: Alignment;
impl<const N: usize> Padding<N>
where
Align<N>: Alignment,
{
#[inline]
pub const fn new() -> Padding<N> {
Padding(mem::MaybeUninit::uninit())
}
}
impl<const N: usize> fmt::Debug for Padding<N>
where
Align<N>: Alignment,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (buf, len) = const {
let mut buf = *b"Padding<{1 << 63}>";
let len = if N < (1 << 10) {
buf[14] = b'0' + (N.trailing_zeros() as u8);
buf[15] = b'}';
buf[16] = b'>';
17
} else {
let exp = N.trailing_zeros() as u8;
buf[14] = b'0' + (exp / 10);
buf[15] = b'0' + (exp % 10);
18
};
(buf, len)
};
let s = unsafe { str::from_utf8_unchecked(&buf[..len]) };
f.pad(s)
}
}
mod sealed {
pub trait Sealed {}
}
pub trait Alignment: sealed::Sealed {
#[doc(hidden)]
const DYN: DynAlign;
#[doc(hidden)]
type Align: 'static + Copy;
#[doc(hidden)]
type Padding: 'static + Copy;
}
macro_rules! align {
(
$($vis:vis struct $A:ident = $align:literal;)*
) => {
$(
#[repr(align($align))]
#[allow(missing_debug_implementations)]
#[derive(Copy, Clone)]
$vis struct $A;
impl sealed::Sealed for Align<$align> {}
impl Alignment for Align<$align> {
const DYN: DynAlign = DynAlign::from_usize($align).unwrap();
type Align = $A;
type Padding = [u8; $align];
}
)*
}
}
align! {
pub struct A0 = 0x1;
pub struct A1 = 0x2;
pub struct A2 = 0x4;
pub struct A3 = 0x8;
pub struct A4 = 0x10;
pub struct A5 = 0x20;
pub struct A6 = 0x40;
pub struct A7 = 0x80;
pub struct A8 = 0x100;
pub struct A9 = 0x200;
pub struct A10 = 0x400;
pub struct A11 = 0x800;
pub struct A12 = 0x1000;
pub struct A13 = 0x2000;
pub struct A14 = 0x4000;
pub struct A15 = 0x8000;
}
#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
align! {
pub struct A16 = 0x10000;
pub struct A17 = 0x20000;
pub struct A18 = 0x40000;
pub struct A19 = 0x80000;
pub struct A20 = 0x100000;
pub struct A21 = 0x200000;
pub struct A22 = 0x400000;
pub struct A23 = 0x800000;
pub struct A24 = 0x1000000;
pub struct A25 = 0x2000000;
pub struct A26 = 0x4000000;
pub struct A27 = 0x8000000;
pub struct A28 = 0x10000000;
pub struct A29 = 0x20000000;
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Aligned<T, const N: usize>
where
Align<N>: Alignment,
{
align: Align<N>,
inner: T,
}
impl<T, const N: usize> Aligned<T, N>
where
Align<N>: Alignment,
{
pub const fn new(inner: T) -> Aligned<T, N> {
Aligned {
align: Align([]),
inner,
}
}
pub const fn into_inner(self) -> T {
let inner = unsafe { mem::transmute_copy(&self) };
mem::forget(self);
inner
}
}
impl<T, const N: usize> ops::Deref for Aligned<T, N>
where
Align<N>: Alignment,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner
}
}
impl<T, const N: usize> ops::DerefMut for Aligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}
#[cfg_attr(feature = "nightly", marker)]
pub trait Unpadded {}
impl<T: Unpadded, const N: usize> Unpadded for [T; N] {}
impl<T> Unpadded for PhantomData<T> {}
impl<const N: usize> Unpadded for Align<N> where Align<N>: Alignment {}
impl<const N: usize> Unpadded for Padding<N> where Align<N>: Alignment {}
#[cfg(feature = "nightly")]
impl<T> Unpadded for [T; 0] {}
macro_rules! impl_unpadded {
($($t:ty),* $(,)?) => {
$(
impl Unpadded for $t {}
)*
}
}
impl_unpadded! {
bool,
u8,
u16,
u32,
u64,
u128,
usize,
i8,
i16,
i32,
i64,
i128,
isize,
char,
NonZero<u8>,
NonZero<u16>,
NonZero<u32>,
NonZero<u64>,
NonZero<u128>,
NonZero<usize>,
NonZero<i8>,
NonZero<i16>,
NonZero<i32>,
NonZero<i64>,
NonZero<i128>,
NonZero<isize>,
NonZero<char>,
(),
}
#[repr(C)]
union MisalignedPadding<T, const N: usize>
where
Align<N>: Alignment,
{
padding: Padding<N>,
value: mem::ManuallyDrop<T>,
}
#[repr(C)]
pub struct Misaligned<T: Unpadded, const N: usize>
where
Align<N>: Alignment,
{
align: Align<N>,
padding: mem::MaybeUninit<MisalignedPadding<T, N>>,
value: mem::MaybeUninit<T>,
}
impl<T: Unpadded, const N: usize> Misaligned<T, N>
where
Align<N>: Alignment,
{
pub(crate) const OFFSET: usize = mem::offset_of!(Misaligned<T, N>, value) - align_of::<T>();
pub const fn new(inner: T) -> Misaligned<T, N> {
let mut base: Self = Misaligned {
align: Align([]),
padding: mem::MaybeUninit::uninit(),
value: mem::MaybeUninit::uninit(),
};
base.as_mut_uninit().write(inner);
base
}
const fn as_uninit(&self) -> &mem::MaybeUninit<T> {
unsafe {
&*ptr::from_ref(self)
.byte_add(Self::OFFSET)
.cast::<T>()
.cast::<mem::MaybeUninit<T>>()
}
}
const fn as_mut_uninit(&mut self) -> &mut mem::MaybeUninit<T> {
unsafe {
&mut *ptr::from_mut(self)
.byte_add(Self::OFFSET)
.cast::<T>()
.cast::<mem::MaybeUninit<T>>()
}
}
pub const fn into_inner(self) -> T {
let inner = unsafe { self.as_uninit().assume_init_read() };
mem::forget(self);
inner
}
}
impl<T: Unpadded, const N: usize> ops::Deref for Misaligned<T, N>
where
Align<N>: Alignment,
{
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.as_uninit().assume_init_ref() }
}
}
impl<T: Unpadded, const N: usize> ops::DerefMut for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.as_mut_uninit().assume_init_mut() }
}
}
impl<T: Unpadded, const N: usize> Drop for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn drop(&mut self) {
unsafe { self.as_mut_uninit().assume_init_drop() }
}
}
#[cfg_attr(any(feature = "nightly", coverage_nightly), coverage(off))]
#[cfg_attr(test, mutants::skip)]
mod trivial_impls {
use core::{cmp, fmt, hash, mem};
use crate::core::{Align, Aligned, Alignment, Misaligned, Padding, Unpadded};
impl<const N: usize> PartialEq for Align<N>
where
Align<N>: Alignment,
{
#[inline]
fn eq(&self, _: &Self) -> bool {
true
}
}
impl<const N: usize> Eq for Align<N> where Align<N>: Alignment {}
#[expect(clippy::non_canonical_partial_ord_impl)]
impl<const N: usize> PartialOrd for Align<N>
where
Align<N>: Alignment,
{
#[inline]
fn partial_cmp(&self, _: &Align<N>) -> Option<cmp::Ordering> {
Some(cmp::Ordering::Equal)
}
}
impl<const N: usize> Ord for Align<N>
where
Align<N>: Alignment,
{
#[inline]
fn cmp(&self, _: &Align<N>) -> cmp::Ordering {
cmp::Ordering::Equal
}
}
impl<const N: usize> hash::Hash for Align<N>
where
Align<N>: Alignment,
{
#[inline]
fn hash<H: hash::Hasher>(&self, _: &mut H) {}
}
impl<const N: usize> Default for Align<N>
where
Align<N>: Alignment,
{
#[inline]
fn default() -> Align<N> {
Align([])
}
}
impl<const N: usize> PartialEq for Padding<N>
where
Align<N>: Alignment,
{
#[inline]
fn eq(&self, _: &Self) -> bool {
true
}
}
impl<const N: usize> Eq for Padding<N> where Align<N>: Alignment {}
#[expect(clippy::non_canonical_partial_ord_impl)]
impl<const N: usize> PartialOrd for Padding<N>
where
Align<N>: Alignment,
{
#[inline]
fn partial_cmp(&self, _: &Padding<N>) -> Option<cmp::Ordering> {
Some(cmp::Ordering::Equal)
}
}
impl<const N: usize> Ord for Padding<N>
where
Align<N>: Alignment,
{
#[inline]
fn cmp(&self, _: &Padding<N>) -> cmp::Ordering {
cmp::Ordering::Equal
}
}
impl<const N: usize> hash::Hash for Padding<N>
where
Align<N>: Alignment,
{
#[inline]
fn hash<H: hash::Hasher>(&self, _: &mut H) {}
}
impl<const N: usize> Default for Padding<N>
where
Align<N>: Alignment,
{
#[inline]
fn default() -> Padding<N> {
Padding(mem::MaybeUninit::uninit())
}
}
impl<T: Unpadded + Clone, const N: usize> Clone for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn clone(&self) -> Misaligned<T, N> {
Misaligned::new((**self).clone())
}
}
impl<T: Unpadded + PartialEq, const N: usize> PartialEq for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn eq(&self, other: &Misaligned<T, N>) -> bool {
**self == **other
}
}
impl<T: Unpadded + Eq, const N: usize> Eq for Misaligned<T, N> where Align<N>: Alignment {}
impl<T: Unpadded + PartialOrd, const N: usize> PartialOrd for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn partial_cmp(&self, other: &Misaligned<T, N>) -> Option<cmp::Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
}
impl<T: Unpadded + Ord, const N: usize> Ord for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn cmp(&self, other: &Misaligned<T, N>) -> cmp::Ordering {
Ord::cmp(&**self, &**other)
}
}
impl<T: Unpadded + hash::Hash, const N: usize> hash::Hash for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn hash<H: hash::Hasher>(&self, state: &mut H) {
hash::Hash::hash(&**self, state);
}
}
impl<T: Unpadded + Default, const N: usize> Default for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn default() -> Misaligned<T, N> {
Misaligned::new(Default::default())
}
}
macro_rules! fmt_impl_aligned {
(
$($trait:ident),* $(,)?
) => {
$(
impl<T: fmt::$trait, const N: usize> fmt::$trait for Aligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::$trait::fmt(&**self, f)
}
}
)*
}
}
macro_rules! fmt_impl_misaligned {
($($trait:ident),* $(,)?) => {
$(
impl<T: Unpadded + fmt::$trait, const N: usize> fmt::$trait for Misaligned<T, N>
where
Align<N>: Alignment,
{
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::$trait::fmt(&**self, f)
}
}
)*
}
}
fmt_impl_aligned! {
Binary,
Debug,
Display,
LowerExp,
LowerHex,
Octal,
Pointer,
UpperExp,
UpperHex,
}
fmt_impl_misaligned! {
Binary,
Debug,
Display,
LowerExp,
LowerHex,
Octal,
Pointer,
UpperExp,
UpperHex,
}
}
#[cfg(test)]
mod tests {
use core::{
mem::align_of,
sync::atomic::{AtomicUsize, Ordering},
};
use crate::core::{Align, Alignment, Padding, Unpadded, aligned, misaligned};
macro_rules! check_aligned {
($t:ty, $align:literal) => {
let mut val = aligned::<$t, $align>(0);
*val = 1;
assert_eq!(*val, 1);
assert_eq!(val.into_inner(), 1);
assert_eq!(
(&raw const *aligned::<$t, $align>(0)).align_offset($align),
0,
concat!(stringify!($t), " was not ", stringify!($align), "-aligned"),
);
};
}
macro_rules! check_misaligned {
($value:literal: $t:ty, $align:literal) => {
let val = misaligned::<$t, $align>($value);
assert_eq!(
*val, $value,
concat!(
stringify!($t),
" when ",
stringify!($align),
"-misaligned has incorrect value"
),
);
assert_eq!(
val.into_inner(),
$value,
concat!(
stringify!($t),
" when ",
stringify!($align),
"-misaligned has incorrect value"
),
);
let mut val = misaligned::<$t, $align>(0);
*val = $value;
assert_eq!(
*val, $value,
concat!(
stringify!($t),
" when ",
stringify!($align),
"-misaligned has incorrect value"
),
);
let mut power = align_of::<$t>();
loop {
power <<= 1;
if power >= $align {
break;
}
assert_ne!(
(&raw const *val).align_offset(power),
0,
concat!(
stringify!($t),
" when ",
stringify!($align),
"-misaligned was {}-aligned"
),
power,
);
}
};
}
fn box_padding<const N: usize>() -> Box<Padding<N>>
where
Align<N>: Alignment,
{
unsafe { Box::new_uninit().assume_init() }
}
fn box_align<const N: usize>() -> Box<Align<N>>
where
Align<N>: Alignment,
{
unsafe { Box::new_uninit().assume_init() }
}
#[test]
fn test_debug_padding() {
assert_eq!(
format!("{:?}", box_padding::<{ 1 << 0 }>()),
"Padding<{1 << 0}>"
);
assert_eq!(
format!("{:?}", box_padding::<{ 1 << 9 }>()),
"Padding<{1 << 9}>"
);
assert_eq!(
format!("{:?}", box_padding::<{ 1 << 10 }>()),
"Padding<{1 << 10}>"
);
assert_eq!(
format!("{:?}", box_padding::<{ 1 << 11 }>()),
"Padding<{1 << 11}>"
);
assert_eq!(
format!("{:?}", box_padding::<{ 1 << 21 }>()),
"Padding<{1 << 21}>"
);
}
#[test]
fn test_debug_align() {
assert_eq!(
format!("{:?}", box_align::<{ 1 << 0 }>()),
"Align<{1 << 0}>"
);
assert_eq!(
format!("{:?}", box_align::<{ 1 << 9 }>()),
"Align<{1 << 9}>"
);
assert_eq!(
format!("{:?}", box_align::<{ 1 << 10 }>()),
"Align<{1 << 10}>"
);
assert_eq!(
format!("{:?}", box_align::<{ 1 << 11 }>()),
"Align<{1 << 11}>"
);
assert_eq!(
format!("{:?}", box_align::<{ 1 << 21 }>()),
"Align<{1 << 21}>"
);
}
#[test]
fn test_underaligned() {
check_aligned!(u8, 1);
check_aligned!(u16, 1);
check_aligned!(u16, 2);
check_aligned!(u32, 1);
check_aligned!(u32, 2);
check_aligned!(u32, 4);
check_aligned!(u64, 1);
check_aligned!(u64, 2);
check_aligned!(u64, 4);
check_aligned!(u64, 8);
check_aligned!(u128, 1);
check_aligned!(u128, 2);
check_aligned!(u128, 4);
check_aligned!(u128, 8);
check_aligned!(u128, 16);
}
#[test]
fn test_overaligned() {
check_aligned!(u8, 2);
check_aligned!(u8, 4);
check_aligned!(u8, 8);
check_aligned!(u8, 16);
check_aligned!(u8, 32);
check_aligned!(u8, 64);
check_aligned!(u8, 128);
check_aligned!(u8, 256);
check_aligned!(u8, 512);
check_aligned!(u16, 4);
check_aligned!(u16, 8);
check_aligned!(u16, 16);
check_aligned!(u16, 32);
check_aligned!(u16, 64);
check_aligned!(u16, 128);
check_aligned!(u16, 256);
check_aligned!(u16, 512);
check_aligned!(u32, 8);
check_aligned!(u32, 16);
check_aligned!(u32, 32);
check_aligned!(u32, 64);
check_aligned!(u32, 128);
check_aligned!(u32, 256);
check_aligned!(u32, 512);
check_aligned!(u64, 16);
check_aligned!(u64, 32);
check_aligned!(u64, 64);
check_aligned!(u64, 128);
check_aligned!(u64, 256);
check_aligned!(u64, 512);
check_aligned!(u128, 32);
check_aligned!(u128, 64);
check_aligned!(u128, 128);
check_aligned!(u128, 256);
check_aligned!(u128, 512);
}
#[test]
fn test_padding_size() {
assert_eq!(size_of::<Padding<1>>(), 1);
assert_eq!(size_of::<Padding<2>>(), 2);
assert_eq!(size_of::<Padding<4>>(), 4);
assert_eq!(size_of::<Padding<8>>(), 8);
assert_eq!(size_of::<Padding<16>>(), 16);
assert_eq!(size_of::<Padding<32>>(), 32);
assert_eq!(size_of::<Padding<64>>(), 64);
assert_eq!(size_of::<Padding<128>>(), 128);
assert_eq!(size_of::<Padding<256>>(), 256);
assert_eq!(size_of::<Padding<512>>(), 512);
}
#[test]
fn test_not_misaligned() {
check_misaligned!(0x11: u8, 1);
check_misaligned!(0x1122: u16, 1);
check_misaligned!(0x1122: u16, 2);
check_misaligned!(0x1122: u32, 1);
check_misaligned!(0x11223344: u32, 2);
check_misaligned!(0x11223344: u32, 4);
check_misaligned!(0x1122334455667788: u64, 1);
check_misaligned!(0x1122334455667788: u64, 2);
check_misaligned!(0x1122334455667788: u64, 4);
check_misaligned!(0x1122334455667788: u64, 8);
check_misaligned!(0x11223344556677887766554433221100: u128, 1);
check_misaligned!(0x11223344556677887766554433221100: u128, 2);
check_misaligned!(0x11223344556677887766554433221100: u128, 4);
check_misaligned!(0x11223344556677887766554433221100: u128, 8);
check_misaligned!(0x11223344556677887766554433221100: u128, 16);
}
#[test]
fn test_misaligned() {
check_misaligned!(0x11: u8, 2);
check_misaligned!(0x11: u8, 4);
check_misaligned!(0x11: u8, 8);
check_misaligned!(0x11: u8, 16);
check_misaligned!(0x11: u8, 32);
check_misaligned!(0x11: u8, 64);
check_misaligned!(0x11: u8, 128);
check_misaligned!(0x11: u8, 256);
check_misaligned!(0x11: u8, 512);
check_misaligned!(0x1122: u16, 4);
check_misaligned!(0x1122: u16, 8);
check_misaligned!(0x1122: u16, 16);
check_misaligned!(0x1122: u16, 32);
check_misaligned!(0x1122: u16, 64);
check_misaligned!(0x1122: u16, 128);
check_misaligned!(0x1122: u16, 256);
check_misaligned!(0x1122: u16, 512);
check_misaligned!(0x11223344: u32, 8);
check_misaligned!(0x11223344: u32, 16);
check_misaligned!(0x11223344: u32, 32);
check_misaligned!(0x11223344: u32, 64);
check_misaligned!(0x11223344: u32, 128);
check_misaligned!(0x11223344: u32, 256);
check_misaligned!(0x11223344: u32, 512);
check_misaligned!(0x1122334455667788: u64, 16);
check_misaligned!(0x1122334455667788: u64, 32);
check_misaligned!(0x1122334455667788: u64, 64);
check_misaligned!(0x1122334455667788: u64, 128);
check_misaligned!(0x1122334455667788: u64, 256);
check_misaligned!(0x1122334455667788: u64, 512);
check_misaligned!(0x11223344556677887766554433221100: u128, 32);
check_misaligned!(0x11223344556677887766554433221100: u128, 64);
check_misaligned!(0x11223344556677887766554433221100: u128, 128);
check_misaligned!(0x11223344556677887766554433221100: u128, 256);
check_misaligned!(0x11223344556677887766554433221100: u128, 512);
}
fn try_misaligned_drop<const N: usize>(counter: &AtomicUsize) {
struct MyTest<'a>(usize, &'a AtomicUsize);
impl Unpadded for MyTest<'_> {}
impl Drop for MyTest<'_> {
fn drop(&mut self) {
if self.0 == 0x1122 {
self.1.fetch_add(1, Ordering::Relaxed);
}
}
}
let _ = misaligned::<MyTest, 1>(MyTest(0x1122, counter));
let _ = misaligned::<MyTest, 1>(MyTest(0, counter));
}
#[test]
fn test_misaligned_drop() {
let counter = AtomicUsize::new(0);
try_misaligned_drop::<1>(&counter);
try_misaligned_drop::<2>(&counter);
try_misaligned_drop::<4>(&counter);
try_misaligned_drop::<8>(&counter);
try_misaligned_drop::<16>(&counter);
assert_eq!(counter.load(Ordering::Relaxed), 5);
}
}