zephyr/
align.rs

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