Expand description

Structures providing guarantees on byte sequence alignment.

For some crucial data it might be beneficial to align them to page boundaries for better cache performance. This crate uses the page_size crate to get the page size.

Examples

assert_eq!(page_size::get(), alignment::Page::size());
let possibly_unaligned = [1, 2, 3];
let aligned = AlignedBytes::<alignment::Page>::from(possibly_unaligned);
let ptr = aligned.as_ptr();

assert_eq!(ptr.align_offset(page_size::get()), 0);
assert_eq!(aligned, possibly_unaligned);

To create a new aligned block of bytes it’s easiest to use new_zeroed.

let aligned = AlignedBytes::<alignment::Page>::new_zeroed(1024);
let ptr = aligned.as_ptr();

assert_eq!(ptr.align_offset(page_size::get()), 0);
assert!(aligned.iter().all(|&x| x == 0));

You can also use new to possibly skip initialization. This is unsafe, since the underlying memory might be uninitialized, but may be useful if you immediately want to initialize the memory afterwards.

let mut aligned = unsafe { AlignedBytes::<alignment::Page>::new(1024) };
let ptr = aligned.as_ptr();

assert_eq!(ptr.align_offset(page_size::get()), 0);

// We cannot assert anything else, `aligned` can contain arbitrary bytes.
// To be able to read anything, we must first initialize.

for i in 0..1024 {
    aligned[i] = 1;
}

let ones = std::iter::repeat(1).take(1024).collect::<Vec<u8>>();
assert_eq!(ones, aligned);

If you want a safe way to initialize the bytes, there is new_initialize that initializes all bytes with a function of their index.

let aligned = AlignedBytes::<alignment::Page>::new_initialize(8, |i| { i as u8 });
let ptr = aligned.as_ptr();

assert_eq!(ptr.align_offset(page_size::get()), 0);
assert_eq!(aligned, [0, 1, 2, 3, 4, 5, 6, 7]);

SIMD

Loading block-aligned bytes into SIMD is generally preferred over unaligned. The SIMD alignment constructs are enabled with the simd default feature.

let possibly_unaligned = [1, 2, 3];
let aligned = AlignedBytes::<alignment::SimdBlock>::from(possibly_unaligned);
let ptr = aligned.as_ptr();

assert_eq!(ptr.align_offset(alignment::SimdBlock::size()), 0);
assert_eq!(aligned, possibly_unaligned);

Note on alignment checking

Checking alignment is hard. pointer::align_offset can return usize::MAX without any reason and it explicitly says that it should not be relied on for correctness.

The above examples ignore that for assertion purposes, because there is no better way. In reality, the check in align_offset just checks the remainder of the pointer’s integer representation, plus some additional bounds checking, so it is fine for testing purposes on most platforms.

This is an additional benefit of using aligners, as it is a strong guarantee on alignment.

If you disagree with this assessment, feel free to contribute to this StackOverflow question.

Modules

Types of possible alignment type arguments for AlignedBytes.

Structs

Thin wrapper that represents an AlignedSlice of size at most the alignment size.
Iterator over AlignedBlocks of a given aligned bytes span.
Bytes aligned to a boundary represented by A.
Slice of bytes aligned to a boundary represented by A.

Traits

Common trait for AlignedBytes for all different alignments.