Skip to main content

ab_io_type/
alignment.rs

1//! Alignment of a type or value, in its own module so that only its constructors can create it
2
3use crate::trivial_type::TrivialType;
4use core::hint;
5
6/// Alignment of a type or value.
7///
8/// It is stored as its power of two, so the compiler knows that the alignment in bytes is a power
9/// of two, and code that uses it can compute padding with plain `%` that compiles to bit masks.
10/// Alignments compare like their values in bytes.
11#[derive(Debug, Copy, Clone)]
12#[derive_const(PartialEq, Eq, PartialOrd, Ord)]
13pub struct Alignment {
14    /// Power of two of the alignment, at most the power of [`Alignment::MAX`]
15    pub mut(self) power: u8,
16}
17
18impl Alignment {
19    /// The largest alignment supported, 16 bytes.
20    ///
21    /// No [`TrivialType`] has a larger alignment.
22    pub const MAX: Self = {
23        let Ok(power) = u8::try_from(16u8.ilog2()) else {
24            unreachable!();
25        };
26        Self { power }
27    };
28
29    /// Alignment from its power of two, `None` if it would be larger than [`Alignment::MAX`]
30    #[inline(always)]
31    pub const fn from_power(power: u8) -> Option<Self> {
32        if power > Self::MAX.power {
33            return None;
34        }
35
36        Some(Self { power })
37    }
38
39    /// Alignment of `T` in metadata, see [`TrivialType::ALIGNMENT`].
40    ///
41    /// [`TrivialType`] requires an alignment of at most [`Alignment::MAX`], and a call doesn't
42    /// compile for an implementation that breaks this requirement. It also doesn't compile when
43    /// `T::ALIGNMENT` is smaller than `align_of::<T>()`.
44    #[inline(always)]
45    pub const fn of<T>() -> Self
46    where
47        T: TrivialType,
48    {
49        const {
50            assert!(
51                align_of::<T>() <= usize::from(T::ALIGNMENT.get()),
52                "Alignment of the type is larger than `TrivialType::ALIGNMENT`"
53            );
54            T::ALIGNMENT
55        }
56    }
57
58    /// The alignment in bytes
59    #[inline(always)]
60    pub const fn get(self) -> u8 {
61        // SAFETY: The field is only set in this module (`mut(self)`), by the definition of `MAX`
62        // and by `from_power()`, which rejects powers larger than that of `MAX`. This tells the
63        // compiler that the alignment is at most `Alignment::MAX`, also when it was read from
64        // memory.
65        unsafe {
66            hint::assert_unchecked(self.power <= Self::MAX.power);
67        }
68
69        1 << self.power
70    }
71
72    /// Whether `slice` starts at an address aligned to `self`
73    #[inline(always)]
74    pub fn is_slice_aligned<T>(self, slice: &[T]) -> bool
75    where
76        T: TrivialType,
77    {
78        let alignment = usize::from(self.get());
79        slice.as_ptr().addr().is_multiple_of(alignment)
80    }
81}