#![no_std]
#![cfg_attr(feature = "freeze", feature(freeze))]
#[cfg(feature = "freeze")]
use core::marker::Freeze;
use core::{
fmt,
hash::Hash,
panic::{RefUnwindSafe, UnwindSafe},
};
#[cfg_attr(feature = "bytemuck", doc = "[`bytemuck::Pod`]")]
#[cfg_attr(
not(feature = "bytemuck"),
doc = "[`bytemuck::Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html)"
)]
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct AlignedZst<const ALIGNMENT: usize>
where
Alignment<ALIGNMENT>: SupportedAlignment,
{
inner: <Alignment<ALIGNMENT> as SupportedAlignment>::AlignedZst,
}
impl<const ALIGNMENT: usize> fmt::Debug for AlignedZst<ALIGNMENT>
where
Alignment<ALIGNMENT>: SupportedAlignment,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AlignedZst<{}> {{ .. }}", ALIGNMENT)
}
}
#[cfg(feature = "bytemuck")]
unsafe impl<const ALIGNMENT: usize> bytemuck::Zeroable for AlignedZst<ALIGNMENT> where
Alignment<ALIGNMENT>: SupportedAlignment
{
}
#[cfg(feature = "bytemuck")]
unsafe impl<const ALIGNMENT: usize> bytemuck::Pod for AlignedZst<ALIGNMENT> where
Alignment<ALIGNMENT>: SupportedAlignment
{
}
mod sealed {
pub trait Sealed {}
}
impl<const N: usize> sealed::Sealed for Alignment<N> {}
pub struct Alignment<const N: usize>;
pub unsafe trait SupportedAlignment: sealed::Sealed {
cfg_if::cfg_if! {
if #[cfg(feature = "freeze")] {
#[doc(hidden)]
type AlignedZst: Sized + Default + Copy + Ord + Hash + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe + Freeze + 'static;
} else {
#[doc(hidden)]
type AlignedZst: Sized + Default + Copy + Ord + Hash + Send + Sync + Unpin + UnwindSafe + RefUnwindSafe + 'static;
}
}
}
macro_rules! make_zsts {
( $($typename:ident = $alignment:literal;)* ) => { $(
#[doc = concat!("Is a ZST with alignment ", stringify!($alignment), ".")]
#[doc(hidden)]
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(align($alignment))]
pub struct $typename;
unsafe impl SupportedAlignment for Alignment<$alignment> {
type AlignedZst = $typename;
}
)* };
}
make_zsts! {
Align1 = 1;
Align2 = 2;
Align4 = 4;
Align8 = 8;
Align16 = 16;
Align32 = 32;
Align64 = 64;
Align128 = 128;
Align256 = 256;
Align512 = 512;
Align1024 = 1024;
Align2048 = 2048;
Align4096 = 4096;
Align8192 = 8192;
Align16384 = 16384;
Align32768 = 32768;
Align65536 = 65536;
Align131072 = 131072;
Align262144 = 262144;
Align524288 = 524288;
Align1048576 = 1048576;
Align2097152 = 2097152;
Align4194304 = 4194304;
Align8388608 = 8388608;
Align16777216 = 16777216;
Align33554432 = 33554432;
Align67108864 = 67108864;
Align134217728 = 134217728;
Align268435456 = 268435456;
Align536870912 = 536870912;
}
#[cfg(test)]
mod tests {
extern crate std;
use crate::{AlignedZst, Alignment, SupportedAlignment};
#[test]
fn it_works() {
#[derive(Default, Clone, Copy)]
struct AlignedThing<const N: usize, T>
where
Alignment<N>: SupportedAlignment,
{
_aligned: AlignedZst<N>,
value: T,
}
assert_eq!(core::mem::align_of::<AlignedThing<64, u8>>(), 64);
assert_eq!(
core::mem::align_of::<AlignedThing<4, u64>>(),
core::cmp::max(4, core::mem::align_of::<u64>())
);
assert_eq!(
core::mem::align_of::<AlignedThing<536870912, u8>>(),
536870912
);
let x: [AlignedThing<64, u8>; 2] =
[AlignedThing { value: 42, _aligned: Default::default() }; 2];
assert_eq!(
(&x[1].value as *const _ as usize)
- (&x[0].value as *const _ as usize),
64
);
}
}