From 9d1cf125f8ba4e509d5eacc2193b6b2c0999f9e1 Mon Sep 17 00:00:00 2001 From: Mathis Bottinelli Date: Sun, 18 May 2025 13:46:42 +0200 Subject: [PATCH] Implement `ptr::try_cast_aligned` and `NonNull::try_cast_aligned`. --- library/core/src/ptr/const_ptr.rs | 28 ++++++++++++++++++++++++++++ library/core/src/ptr/mut_ptr.rs | 28 ++++++++++++++++++++++++++++ library/core/src/ptr/non_null.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 35089b4853d7f..f6109cafe86b1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -66,6 +66,34 @@ impl *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::().is_some()); + /// + /// let unaligned: *const u8 = 0x1001 as _; + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::().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(self) -> Option<*const U> { + if self.is_aligned_to(align_of::()) { 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 9cf251742d427..2662a4fdc3138 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -48,6 +48,34 @@ impl *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::().is_some()); + /// + /// let unaligned: *mut u8 = 0x1001 as _; + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::().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(self) -> Option<*mut U> { + if self.is_aligned_to(align_of::()) { 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 8b31328de047f..bb344c6a0d316 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -490,6 +490,35 @@ impl NonNull { 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 = NonNull::new(0x1000 as _).unwrap(); + /// + /// // i32 has at most 4-byte alignment, so this will succeed + /// assert!(aligned.try_cast_aligned::().is_some()); + /// + /// let unaligned: NonNull = NonNull::new(0x1001 as _).unwrap(); + /// + /// // i32 has at least 2-byte alignment, so this will fail + /// assert!(unaligned.try_cast_aligned::().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(self) -> Option> { + if self.is_aligned_to(align_of::()) { 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