Skip to main content

hermes_simd_core/
align.rs

1//! Typestate markers for statically and dynamically guaranteed slice alignment.
2//!
3//! Provides types that represent memory alignment bounds at the type level, allowing
4//! SIMD operations to dispatch to faster aligned loading instructions (`load_aligned`)
5//! instead of unaligned loading instructions safely.
6
7/// Trait representing a memory alignment guarantee.
8///
9/// Implemented by Zero-Sized Types (ZSTs) representing the alignment layout of the slice.
10pub trait Alignment: crate::private::Sealed + Send + Sync + 'static + Copy + Clone {
11    /// The alignment boundary in bytes, if statically guaranteed.
12    ///
13    /// Set to `Some(N)` for aligned views where `N` is a power of two, or `None` if
14    /// there is no static alignment guarantee (i.e. `Unaligned`).
15    const ALIGNMENT: Option<usize>;
16
17    /// Whether static alignment is guaranteed.
18    const IS_ALIGNED: bool;
19
20    /// The alignment boundary in bytes (0 if unaligned).
21    const ALIGN_BYTES: usize;
22}
23
24/// A static alignment guarantee of `A` bytes.
25///
26/// Guaranteed at compile time to represent a power-of-two alignment boundary.
27/// If `A` is not a power of two, it will fail to compile due to a const assertion check.
28///
29/// # Examples
30///
31/// ```rust
32/// use hermes_simd_core::align::{Aligned, Alignment};
33///
34/// assert_eq!(Aligned::<32>::ALIGNMENT, Some(32));
35/// ```
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct Aligned<const A: usize>;
38
39impl<const A: usize> Aligned<A> {
40    const _CHECK_POWER_OF_TWO: () = {
41        assert!(
42            A.is_power_of_two(),
43            "Alignment boundary must be a power of two"
44        );
45    };
46}
47
48/// No static alignment guarantee.
49///
50/// Represents raw slice memory that might start at any byte boundary. Dispatches
51/// to unaligned memory access operations.
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct Unaligned;
54
55impl<const A: usize> Alignment for Aligned<A> {
56    const ALIGNMENT: Option<usize> = {
57        // Evaluate the const assertion when the trait is implemented.
58        let _ = Self::_CHECK_POWER_OF_TWO;
59        Some(A)
60    };
61    const IS_ALIGNED: bool = true;
62    const ALIGN_BYTES: usize = A;
63}
64
65impl Alignment for Unaligned {
66    const ALIGNMENT: Option<usize> = None;
67    const IS_ALIGNED: bool = false;
68    const ALIGN_BYTES: usize = 0;
69}
70
71impl<const A: usize> crate::private::Sealed for Aligned<A> {}
72impl crate::private::Sealed for Unaligned {}
73
74/// Helper to check if the alignment `Align` is sufficient for architecture `Arch` vector register width.
75#[inline(always)]
76pub fn is_aligned_for_arch<Arch: crate::arch::SimdArch, Align: Alignment>() -> bool {
77    if !Align::IS_ALIGNED {
78        return false;
79    }
80    let req_align = Arch::REGISTER_WIDTH_BITS as usize / 8;
81    Align::ALIGN_BYTES >= req_align
82}