Description
Proposal
Problem statement
We often use usize
to represent the alignment of a type. However, on a 64-bit machine there are only 64 valid alignments, which is under 0.000_000_000_000_000_35% of the valid values of the type -- and, realistically, there are only ≈10 useful alignments. (Sure, it's legal to write repr(align(1152921504606846976))
, but nobody ever would.)
It's also common to use the special property of valid alignments -- that they're powers of two -- to optimize various operations in ways that produce meaningless results for other values. For example, ptr % align
is written as ptr & (align - 1)
, but that has "no meaning" for invalid alignment values.
With a custom type for alignments we can provide APIs that can safely take advantage of these properties.
Motivation, use-cases
Layout::padding_needed_for
takes align: usize
, and thus needs the note
The return value of this function has no meaning if align is not a power-of-two.
if it took a specific alignment type, that wouldn't be a concern. And needing to call .pading_needed_for(Alignment::of::<T>())
(say) instead of .padding_needed_for(align_of::<T>())
is no hardship for the caller.
Similarly, <*const T>::is_aligned_to
also takes align: usize
, and its tracking issue (rust-lang/rust#96284) has an open question about how to handle invalid alignments passed to it.
Already today, Layout
requires that its alignment be a valid alignment. Having a type with the invariant that it's a valid alignment allowed making a method safe when it would have otherwise required unsafe
(rust-lang/rust#99117 (comment)).
Solution sketches
I propose something like the following type:
// in core::ptr
pub struct Alignment(…);
impl Copy + Clone + Ord + PartialOrd + Eq + PartialEq + Hash + Debug { … }
impl Alignment {
/// Alignment of `T`
pub const fn of<T>() -> Self;
/// Checked constructor from `usize`
pub const fn new(align: usize) -> Option<Self>;
/// Unchecked constructor from `usize`
pub const unsafe fn new_unchecked(align: usize) -> Self;
/// Get the raw value out again
pub const fn as_usize(self) -> usize;
}
There's a variety of additional things that could go along with that, but aren't essential from the start, like
- Getting a
NonZeroUsize
from the alignment - Various
From
/TryFrom
s to go with thenew
s - A
log2
to turn alignments into0, 1, 2, 3, …
instead of1, 2, 4, 8, …
*const T: Mod<Alignment, Output = usize>
- Additional methods on
Layout
to expose the internalAlignment
and create from anAlignment
(thus avoiding thealign.is_power_of_two()
check in its safe constructor).
Links and related work
A type for this already exists internally in core
: https://github.com/rust-lang/rust/blob/master/library/core/src/mem/valid_align.rs
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.