diff options
| author | Matthias Krüger <476013+matthiaskrgr@users.noreply.github.com> | 2025-05-21 08:05:21 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-05-21 08:05:21 +0200 |
| commit | bb7291e71ba1461d273379a762bb1e5bab9ca8c1 (patch) | |
| tree | 686eb07b543ceb8449660929647f8d1438bc286b | |
| parent | c5920278d398480c49138d71bdcfdaa8bcbfc182 (diff) | |
| parent | 9d1cf125f8ba4e509d5eacc2193b6b2c0999f9e1 (diff) | |
| download | rust-bb7291e71ba1461d273379a762bb1e5bab9ca8c1.tar.gz rust-bb7291e71ba1461d273379a762bb1e5bab9ca8c1.zip | |
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: https://github.com/rust-lang/rust/issues/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)
| -rw-r--r-- | library/core/src/ptr/const_ptr.rs | 28 | ||||
| -rw-r--r-- | library/core/src/ptr/mut_ptr.rs | 28 | ||||
| -rw-r--r-- | library/core/src/ptr/non_null.rs | 29 |
3 files changed, 85 insertions, 0 deletions
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 35089b4853d..f6109cafe86 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -66,6 +66,34 @@ impl<T: ?Sized> *const T { self as _ } + /// Try to cast to a pointer of another type by checking aligment. + /// + /// If the pointer is properly aligned to the target type, it will be + /// cast to the target type. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(pointer_try_cast_aligned)] + /// + /// let aligned: *const u8 = 0x1000 as _; + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::<i32>().is_some()); + /// + /// let unaligned: *const u8 = 0x1001 as _; + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::<i32>().is_none()); + /// ``` + #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn try_cast_aligned<U>(self) -> Option<*const U> { + if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None } + } + /// Uses the address value in a new pointer of another type. /// /// This operation will ignore the address part of its `meta` operand and discard existing diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 9cf251742d4..2662a4fdc31 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -48,6 +48,34 @@ impl<T: ?Sized> *mut T { self as _ } + /// Try to cast to a pointer of another type by checking aligment. + /// + /// If the pointer is properly aligned to the target type, it will be + /// cast to the target type. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(pointer_try_cast_aligned)] + /// + /// let aligned: *mut u8 = 0x1000 as _; + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::<i32>().is_some()); + /// + /// let unaligned: *mut u8 = 0x1001 as _; + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::<i32>().is_none()); + /// ``` + #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn try_cast_aligned<U>(self) -> Option<*mut U> { + if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None } + } + /// Uses the address value in a new pointer of another type. /// /// This operation will ignore the address part of its `meta` operand and discard existing diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 8b31328de04..bb344c6a0d3 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -490,6 +490,35 @@ impl<T: ?Sized> NonNull<T> { unsafe { NonNull { pointer: self.as_ptr() as *mut U } } } + /// Try to cast to a pointer of another type by checking aligment. + /// + /// If the pointer is properly aligned to the target type, it will be + /// cast to the target type. Otherwise, `None` is returned. + /// + /// # Examples + /// + /// ```rust + /// #![feature(pointer_try_cast_aligned)] + /// use std::ptr::NonNull; + /// + /// let aligned: NonNull<u8> = NonNull::new(0x1000 as _).unwrap(); + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::<i32>().is_some()); + /// + /// let unaligned: NonNull<u8> = NonNull::new(0x1001 as _).unwrap(); + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::<i32>().is_none()); + /// ``` + #[unstable(feature = "pointer_try_cast_aligned", issue = "141221")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn try_cast_aligned<U>(self) -> Option<NonNull<U>> { + if self.is_aligned_to(align_of::<U>()) { Some(self.cast()) } else { None } + } + /// Adds an offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer |
