Skip to content

Commit bb7291e

Browse files
authored
Rollup merge of #141222 - mathisbot:ptr_trycastaligned, r=tgross35
Implement `ptr::try_cast_aligned` and `NonNull::try_cast_aligned`. Implement three common methods on raw pointers and `NonNull`s: `try_cast_aligned`. ## Related links - Tracking Issue: #141221 ## About `#[inline]` Since the result of a call to `align_of` is a power of two known at compile time, the compiler is able to reduce a call to `try_cast_aligned` to only test and sete (or test and jne if followed by `unwrap`), at least on every tier 1 target's arch. This seemed like a good reason to `#[inline]` the function. - https://godbolt.org/z/ocehvPWMx (raw inlining) - https://godbolt.org/z/3qa4j4Yrn (comparison with no inlining)
2 parents c592027 + 9d1cf12 commit bb7291e

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

library/core/src/ptr/const_ptr.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,34 @@ impl<T: ?Sized> *const T {
6666
self as _
6767
}
6868

69+
/// Try to cast to a pointer of another type by checking aligment.
70+
///
71+
/// If the pointer is properly aligned to the target type, it will be
72+
/// cast to the target type. Otherwise, `None` is returned.
73+
///
74+
/// # Examples
75+
///
76+
/// ```rust
77+
/// #![feature(pointer_try_cast_aligned)]
78+
///
79+
/// let aligned: *const u8 = 0x1000 as _;
80+
///
81+
/// // i32 has at most 4-byte alignment, so this will succeed
82+
/// assert!(aligned.try_cast_aligned::<i32>().is_some());
83+
///
84+
/// let unaligned: *const u8 = 0x1001 as _;
85+
///
86+
/// // i32 has at least 2-byte alignment, so this will fail
87+
/// assert!(unaligned.try_cast_aligned::<i32>().is_none());
88+
/// ```
89+
#[unstable(feature = "pointer_try_cast_aligned", issue = "141221")]
90+
#[must_use = "this returns the result of the operation, \
91+
without modifying the original"]
92+
#[inline]
93+
pub fn try_cast_aligned<U>(self) -> Option<*const U> {
94+
if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None }
95+
}
96+
6997
/// Uses the address value in a new pointer of another type.
7098
///
7199
/// This operation will ignore the address part of its `meta` operand and discard existing

library/core/src/ptr/mut_ptr.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,34 @@ impl<T: ?Sized> *mut T {
4848
self as _
4949
}
5050

51+
/// Try to cast to a pointer of another type by checking aligment.
52+
///
53+
/// If the pointer is properly aligned to the target type, it will be
54+
/// cast to the target type. Otherwise, `None` is returned.
55+
///
56+
/// # Examples
57+
///
58+
/// ```rust
59+
/// #![feature(pointer_try_cast_aligned)]
60+
///
61+
/// let aligned: *mut u8 = 0x1000 as _;
62+
///
63+
/// // i32 has at most 4-byte alignment, so this will succeed
64+
/// assert!(aligned.try_cast_aligned::<i32>().is_some());
65+
///
66+
/// let unaligned: *mut u8 = 0x1001 as _;
67+
///
68+
/// // i32 has at least 2-byte alignment, so this will fail
69+
/// assert!(unaligned.try_cast_aligned::<i32>().is_none());
70+
/// ```
71+
#[unstable(feature = "pointer_try_cast_aligned", issue = "141221")]
72+
#[must_use = "this returns the result of the operation, \
73+
without modifying the original"]
74+
#[inline]
75+
pub fn try_cast_aligned<U>(self) -> Option<*mut U> {
76+
if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None }
77+
}
78+
5179
/// Uses the address value in a new pointer of another type.
5280
///
5381
/// This operation will ignore the address part of its `meta` operand and discard existing

library/core/src/ptr/non_null.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,35 @@ impl<T: ?Sized> NonNull<T> {
490490
unsafe { NonNull { pointer: self.as_ptr() as *mut U } }
491491
}
492492

493+
/// Try to cast to a pointer of another type by checking aligment.
494+
///
495+
/// If the pointer is properly aligned to the target type, it will be
496+
/// cast to the target type. Otherwise, `None` is returned.
497+
///
498+
/// # Examples
499+
///
500+
/// ```rust
501+
/// #![feature(pointer_try_cast_aligned)]
502+
/// use std::ptr::NonNull;
503+
///
504+
/// let aligned: NonNull<u8> = NonNull::new(0x1000 as _).unwrap();
505+
///
506+
/// // i32 has at most 4-byte alignment, so this will succeed
507+
/// assert!(aligned.try_cast_aligned::<i32>().is_some());
508+
///
509+
/// let unaligned: NonNull<u8> = NonNull::new(0x1001 as _).unwrap();
510+
///
511+
/// // i32 has at least 2-byte alignment, so this will fail
512+
/// assert!(unaligned.try_cast_aligned::<i32>().is_none());
513+
/// ```
514+
#[unstable(feature = "pointer_try_cast_aligned", issue = "141221")]
515+
#[must_use = "this returns the result of the operation, \
516+
without modifying the original"]
517+
#[inline]
518+
pub fn try_cast_aligned<U>(self) -> Option<NonNull<U>> {
519+
if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None }
520+
}
521+
493522
/// Adds an offset to a pointer.
494523
///
495524
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer

0 commit comments

Comments
 (0)