Skip to content

Commit

Permalink
impl more traits for ptr::Alignment, add mask method
Browse files Browse the repository at this point in the history
  • Loading branch information
clarfonthey committed Sep 16, 2023
1 parent e81f85f commit 26b97a2
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 3 deletions.
129 changes: 127 additions & 2 deletions library/core/src/ptr/alignment.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::convert::{TryFrom, TryInto};
use crate::intrinsics::assert_unsafe_precondition;
use crate::num::NonZeroUsize;
use crate::{cmp, fmt, hash, mem, num};
use crate::{cmp, fmt, hash, mem, num, str};

/// A type storing a `usize` which is a power of two, and thus
/// represents a possible alignment in the rust abstract machine.
Expand Down Expand Up @@ -42,6 +42,7 @@ impl Alignment {
/// This provides the same numerical value as [`mem::align_of`],
/// but in an `Alignment` instead of a `usize`.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub const fn of<T>() -> Self {
// SAFETY: rustc ensures that type alignment is always a power of two.
Expand All @@ -53,6 +54,7 @@ impl Alignment {
///
/// Note that `0` is not a power of two, nor a valid alignment.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub const fn new(align: usize) -> Option<Self> {
if align.is_power_of_two() {
Expand Down Expand Up @@ -98,6 +100,7 @@ impl Alignment {

/// Returns the alignment as a [`NonZeroUsize`]
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub const fn as_nonzero(self) -> NonZeroUsize {
// SAFETY: All the discriminants are non-zero.
Expand All @@ -118,10 +121,39 @@ impl Alignment {
/// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub fn log2(self) -> u32 {
pub const fn log2(self) -> u32 {
self.as_nonzero().trailing_zeros()
}

/// Returns a bit mask that can be used to match this alignment.
///
/// This is equivalent to `!(self.as_usize() - 1)`.
///
/// # Examples
///
/// ```
/// #![feature(ptr_alignment_type)]
/// #![feature(ptr_mask)]
/// use std::ptr::{Alignment, NonNull};
///
/// let one = <NonNull<u8>>::dangling().as_ptr();
/// let four = <NonNull<u32>>::dangling().as_ptr();
///
/// assert_eq!(four.mask(Alignment::of::<u8>().mask()), four);
/// assert_eq!(four.mask(Alignment::of::<u16>().mask()), four);
/// assert_eq!(four.mask(Alignment::of::<u32>().mask()), four);
/// assert_ne!(four.mask(Alignment::of::<u64>().mask()), four);
/// assert_ne!(one.mask(Alignment::of::<u64>().mask()), one);
/// ```
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
#[inline]
pub const fn mask(self) -> usize {
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
!(unsafe { self.as_usize().unchecked_sub(1) })
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
Expand All @@ -131,6 +163,92 @@ impl fmt::Debug for Alignment {
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::Display for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.as_nonzero(), f)
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::Binary for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Binary::fmt(&self.as_nonzero(), f)
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::Octal for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Octal::fmt(&self.as_nonzero(), f)
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::LowerHex for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::LowerHex::fmt(&self.as_nonzero(), f)
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::UpperHex for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(&self.as_nonzero(), f)
}
}

impl Alignment {
// longest string: 1p-128
fn fmt_exp(self, buf: &mut [u8; 6], p: u8) -> &[u8] {
buf[0] = b'1';
buf[1] = p;

let mut shl = self.log2() as u8;
if shl == 0 {
buf[2] = b'0';
return &buf[..3];
}

buf[2] = b'-';
if shl > 100 {
buf[5] = b'0' + shl % 10;
shl /= 10;
buf[4] = b'0' + shl % 10;
shl /= 10;
buf[3] = b'0' + shl % 10;
&buf[..6]
} else if shl > 10 {
buf[4] = b'0' + shl % 10;
shl /= 10;
buf[3] = b'0' + shl % 10;
&buf[..5]
} else {
buf[3] = b'0' + shl % 10;
&buf[..4]
}
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::LowerExp for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0; 6];

// SAFETY: We generate an ASCII string, which is valid UTF-8.
f.pad(unsafe { str::from_utf8_unchecked(self.fmt_exp(&mut buf, b'p')) })
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl fmt::UpperExp for Alignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buf = [0; 6];
// SAFETY: We generate an ASCII string, which is valid UTF-8.
f.pad(unsafe { str::from_utf8_unchecked(self.fmt_exp(&mut buf, b'P')) })
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl TryFrom<NonZeroUsize> for Alignment {
type Error = num::TryFromIntError;
Expand Down Expand Up @@ -193,6 +311,13 @@ impl hash::Hash for Alignment {
}
}

#[unstable(feature = "ptr_alignment_type", issue = "102070")]
impl Default for Alignment {
fn default() -> Alignment {
Alignment::MIN
}
}

#[cfg(target_pointer_width = "16")]
type AlignmentEnum = AlignmentEnum16;
#[cfg(target_pointer_width = "32")]
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
#![feature(get_many_mut)]
#![feature(offset_of)]
#![feature(iter_map_windows)]
#![feature(ptr_alignment_type)]
#![deny(unsafe_op_in_unsafe_fn)]
#![deny(fuzzy_provenance_casts)]

Expand Down
10 changes: 10 additions & 0 deletions library/core/tests/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,3 +1126,13 @@ fn test_const_copy() {
assert!(*ptr2 == 1);
};
}

#[test]
fn alignment_exp_formatting() {
let p0 = Alignment::MIN;
let p1 = Alignment::new(2).unwrap();
let p42 = Alignment::new(1 << 42).unwrap();
assert_eq!(format!("{:e}", p0), "1p0");
assert_eq!(format!("{:E}", p1), "1P-1");
assert_eq!(format!("{:e}", p42), "1p-42");
}
2 changes: 1 addition & 1 deletion tests/ui/fmt/ifmt-unimpl.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ LL | format!("{:X}", "3");
i128
usize
u8
and 20 others
and 21 others
= note: required for `&str` to implement `UpperHex`
note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex`
--> $SRC_DIR/core/src/fmt/rt.rs:LL:COL
Expand Down

0 comments on commit 26b97a2

Please sign in to comment.