Skip to content

Add a specific type for pointer alignment #108

Closed
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions