Skip to content

Commit 26b97a2

Browse files
committed
impl more traits for ptr::Alignment, add mask method
1 parent e81f85f commit 26b97a2

File tree

4 files changed

+139
-3
lines changed

4 files changed

+139
-3
lines changed

library/core/src/ptr/alignment.rs

+127-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::convert::{TryFrom, TryInto};
22
use crate::intrinsics::assert_unsafe_precondition;
33
use crate::num::NonZeroUsize;
4-
use crate::{cmp, fmt, hash, mem, num};
4+
use crate::{cmp, fmt, hash, mem, num, str};
55

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

99101
/// Returns the alignment as a [`NonZeroUsize`]
100102
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
103+
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
101104
#[inline]
102105
pub const fn as_nonzero(self) -> NonZeroUsize {
103106
// SAFETY: All the discriminants are non-zero.
@@ -118,10 +121,39 @@ impl Alignment {
118121
/// assert_eq!(Alignment::new(1024).unwrap().log2(), 10);
119122
/// ```
120123
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
124+
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
121125
#[inline]
122-
pub fn log2(self) -> u32 {
126+
pub const fn log2(self) -> u32 {
123127
self.as_nonzero().trailing_zeros()
124128
}
129+
130+
/// Returns a bit mask that can be used to match this alignment.
131+
///
132+
/// This is equivalent to `!(self.as_usize() - 1)`.
133+
///
134+
/// # Examples
135+
///
136+
/// ```
137+
/// #![feature(ptr_alignment_type)]
138+
/// #![feature(ptr_mask)]
139+
/// use std::ptr::{Alignment, NonNull};
140+
///
141+
/// let one = <NonNull<u8>>::dangling().as_ptr();
142+
/// let four = <NonNull<u32>>::dangling().as_ptr();
143+
///
144+
/// assert_eq!(four.mask(Alignment::of::<u8>().mask()), four);
145+
/// assert_eq!(four.mask(Alignment::of::<u16>().mask()), four);
146+
/// assert_eq!(four.mask(Alignment::of::<u32>().mask()), four);
147+
/// assert_ne!(four.mask(Alignment::of::<u64>().mask()), four);
148+
/// assert_ne!(one.mask(Alignment::of::<u64>().mask()), one);
149+
/// ```
150+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
151+
#[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")]
152+
#[inline]
153+
pub const fn mask(self) -> usize {
154+
// SAFETY: The alignment is always nonzero, and therefore decrementing won't overflow.
155+
!(unsafe { self.as_usize().unchecked_sub(1) })
156+
}
125157
}
126158

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

166+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
167+
impl fmt::Display for Alignment {
168+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169+
fmt::Display::fmt(&self.as_nonzero(), f)
170+
}
171+
}
172+
173+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
174+
impl fmt::Binary for Alignment {
175+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176+
fmt::Binary::fmt(&self.as_nonzero(), f)
177+
}
178+
}
179+
180+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
181+
impl fmt::Octal for Alignment {
182+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183+
fmt::Octal::fmt(&self.as_nonzero(), f)
184+
}
185+
}
186+
187+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
188+
impl fmt::LowerHex for Alignment {
189+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190+
fmt::LowerHex::fmt(&self.as_nonzero(), f)
191+
}
192+
}
193+
194+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
195+
impl fmt::UpperHex for Alignment {
196+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197+
fmt::UpperHex::fmt(&self.as_nonzero(), f)
198+
}
199+
}
200+
201+
impl Alignment {
202+
// longest string: 1p-128
203+
fn fmt_exp(self, buf: &mut [u8; 6], p: u8) -> &[u8] {
204+
buf[0] = b'1';
205+
buf[1] = p;
206+
207+
let mut shl = self.log2() as u8;
208+
if shl == 0 {
209+
buf[2] = b'0';
210+
return &buf[..3];
211+
}
212+
213+
buf[2] = b'-';
214+
if shl > 100 {
215+
buf[5] = b'0' + shl % 10;
216+
shl /= 10;
217+
buf[4] = b'0' + shl % 10;
218+
shl /= 10;
219+
buf[3] = b'0' + shl % 10;
220+
&buf[..6]
221+
} else if shl > 10 {
222+
buf[4] = b'0' + shl % 10;
223+
shl /= 10;
224+
buf[3] = b'0' + shl % 10;
225+
&buf[..5]
226+
} else {
227+
buf[3] = b'0' + shl % 10;
228+
&buf[..4]
229+
}
230+
}
231+
}
232+
233+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
234+
impl fmt::LowerExp for Alignment {
235+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236+
let mut buf = [0; 6];
237+
238+
// SAFETY: We generate an ASCII string, which is valid UTF-8.
239+
f.pad(unsafe { str::from_utf8_unchecked(self.fmt_exp(&mut buf, b'p')) })
240+
}
241+
}
242+
243+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
244+
impl fmt::UpperExp for Alignment {
245+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
246+
let mut buf = [0; 6];
247+
// SAFETY: We generate an ASCII string, which is valid UTF-8.
248+
f.pad(unsafe { str::from_utf8_unchecked(self.fmt_exp(&mut buf, b'P')) })
249+
}
250+
}
251+
134252
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
135253
impl TryFrom<NonZeroUsize> for Alignment {
136254
type Error = num::TryFromIntError;
@@ -193,6 +311,13 @@ impl hash::Hash for Alignment {
193311
}
194312
}
195313

314+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
315+
impl Default for Alignment {
316+
fn default() -> Alignment {
317+
Alignment::MIN
318+
}
319+
}
320+
196321
#[cfg(target_pointer_width = "16")]
197322
type AlignmentEnum = AlignmentEnum16;
198323
#[cfg(target_pointer_width = "32")]

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
#![feature(get_many_mut)]
116116
#![feature(offset_of)]
117117
#![feature(iter_map_windows)]
118+
#![feature(ptr_alignment_type)]
118119
#![deny(unsafe_op_in_unsafe_fn)]
119120
#![deny(fuzzy_provenance_casts)]
120121

library/core/tests/ptr.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1126,3 +1126,13 @@ fn test_const_copy() {
11261126
assert!(*ptr2 == 1);
11271127
};
11281128
}
1129+
1130+
#[test]
1131+
fn alignment_exp_formatting() {
1132+
let p0 = Alignment::MIN;
1133+
let p1 = Alignment::new(2).unwrap();
1134+
let p42 = Alignment::new(1 << 42).unwrap();
1135+
assert_eq!(format!("{:e}", p0), "1p0");
1136+
assert_eq!(format!("{:E}", p1), "1P-1");
1137+
assert_eq!(format!("{:e}", p42), "1p-42");
1138+
}

tests/ui/fmt/ifmt-unimpl.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ LL | format!("{:X}", "3");
1515
i128
1616
usize
1717
u8
18-
and 20 others
18+
and 21 others
1919
= note: required for `&str` to implement `UpperHex`
2020
note: required by a bound in `core::fmt::rt::Argument::<'a>::new_upper_hex`
2121
--> $SRC_DIR/core/src/fmt/rt.rs:LL:COL

0 commit comments

Comments
 (0)