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/TryFroms to go with the news
- A
log2 to turn alignments into 0, 1, 2, 3, … instead of 1, 2, 4, 8, …
*const T: Mod<Alignment, Output = usize>
- Additional methods on
Layout to expose the internal Alignment and create from an Alignment (thus avoiding the align.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.
Proposal
Problem statement
We often use
usizeto 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 writerepr(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 % alignis written asptr & (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_fortakesalign: usize, and thus needs the noteif 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_toalso takesalign: usize, and its tracking issue (rust-lang/rust#96284) has an open question about how to handle invalid alignments passed to it.Already today,
Layoutrequires 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 requiredunsafe(rust-lang/rust#99117 (comment)).Solution sketches
I propose something like the following type:
There's a variety of additional things that could go along with that, but aren't essential from the start, like
NonZeroUsizefrom the alignmentFrom/TryFroms to go with thenewslog2to turn alignments into0, 1, 2, 3, …instead of1, 2, 4, 8, …*const T: Mod<Alignment, Output = usize>Layoutto expose the internalAlignmentand 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.rsWhat 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.