zephyr/align.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
//! Alignment
//!
//! Natively, the align attribute in rust does not allow anything other than an integer literal.
//! However, Zephyr will define the external alignment based on numeric constants. This defines a
//! bit of a trick to enforce alignment of structs to values by defined constants.
//!
//! Thanks to Chayim Refael Friedman for help with this.
#[doc(hidden)]
pub struct AlignAsStruct;
#[doc(hidden)]
pub trait AlignAsTrait<const N: usize> {
type Aligned;
}
macro_rules! impl_alignas {
( $($align:literal),* $(,)? ) => {
$(
const _: () = {
#[repr(align($align))]
pub struct Aligned;
impl AlignAsTrait<$align> for AlignAsStruct {
type Aligned = Aligned;
}
};
)*
};
}
// This can be expanded as needed.
impl_alignas!(1, 2, 4, 8, 16, 32, 64, 128, 256);
/// Align a given struct to a given alignment. To use this, just include `AlignAs<N>` as the first
/// member of the struct.
#[repr(transparent)]
pub struct AlignAs<const N: usize>([<AlignAsStruct as AlignAsTrait<N>>::Aligned; 0])
where
AlignAsStruct: AlignAsTrait<N>;
impl<const N: usize> AlignAs<N>
where AlignAsStruct: AlignAsTrait<N>
{
/// Construct a new AlignAs.
///
/// It is zero bytes, but needs a constructor as the field is private.
pub const fn new() -> AlignAs<N> {
AlignAs([])
}
}