Skip to content

Add a specific type for pointer alignment #108

@scottmcm

Description

@scottmcm

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions