From 4242335b1bd8c304eafdf8dfaa85ea9a08dbf77a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 24 Mar 2022 23:56:33 -0400 Subject: [PATCH 1/3] Additional `*mut [T]` methods Split out from #94247 This adds the following methods to raw slices that already exist on regular slices * `*mut [T]::is_empty` * `*mut [T]::split_at_mut` * `*mut [T]::split_at_unchecked` These methods reduce the amount of unsafe code needed to migrate ChunksMut and related iterators to raw slices (#94247) Co-authored-by:: The 8472 --- library/core/src/ptr/mut_ptr.rs | 105 ++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index bfc89625935d9..66e7ac0d3c462 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1338,6 +1338,111 @@ impl *mut [T] { metadata(self) } + /// Returns `true` if the raw slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_len)] + /// + /// let mut a = [1, 2, 3]; + /// let ptr = &mut a as *mut [_]; + /// assert!(!ptr.is_empty()); + /// ``` + #[inline(always)] + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + pub const fn is_empty(self) -> bool { + self.len() == 0 + } + + /// Divides one mutable raw slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. + /// + /// # Examples + /// + /// ``` + /// #![feature(raw_slice_split)] + /// #![feature(slice_ptr_get)] + /// + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// let ptr = &mut v as *mut [_]; + /// let (left, right) = ptr.split_at_mut(2); + /// unsafe { + /// assert_eq!(&*left, [1, 0]); + /// assert_eq!(&*right, [3, 0, 5, 6]); + /// } + /// ``` + #[inline(always)] + #[track_caller] + #[unstable(feature = "raw_slice_split", issue = "71146")] + pub fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) { + assert!(mid <= self.len()); + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `from_raw_parts_mut`. + unsafe { self.split_at_mut_unchecked(mid) } + } + + /// Divides one mutable raw slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// [`split_at_mut`]: #method.split_at_mut + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(raw_slice_split)] + /// + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let ptr = &mut v as *mut [_]; + /// let (left, right) = ptr.split_at_mut_unchecked(2); + /// assert_eq!(&*left, [1, 0]); + /// assert_eq!(&*right, [3, 0, 5, 6]); + /// (&mut *left)[1] = 2; + /// (&mut *right)[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[inline(always)] + #[unstable(feature = "raw_slice_split", issue = "71146")] + pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { + ( + crate::ptr::slice_from_raw_parts_mut(ptr, mid), + crate::ptr::slice_from_raw_parts_mut(ptr.add(mid), len - mid), + ) + } + } + /// Returns a raw pointer to the slice's buffer. /// /// This is equivalent to casting `self` to `*mut T`, but more type-safe. From a671fa1b15451fc386ed9077466047e19fb74078 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sat, 2 Apr 2022 19:46:12 +0200 Subject: [PATCH 2/3] add tracking issue --- library/core/src/ptr/mut_ptr.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 66e7ac0d3c462..dc63ca809f198 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1382,7 +1382,7 @@ impl *mut [T] { /// ``` #[inline(always)] #[track_caller] - #[unstable(feature = "raw_slice_split", issue = "71146")] + #[unstable(feature = "raw_slice_split", issue = "95595")] pub fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) { assert!(mid <= self.len()); // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which @@ -1426,7 +1426,7 @@ impl *mut [T] { /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` #[inline(always)] - #[unstable(feature = "raw_slice_split", issue = "71146")] + #[unstable(feature = "raw_slice_split", issue = "95595")] pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) { let len = self.len(); let ptr = self.as_mut_ptr(); From b0ca46e90d1304512decc1f9c3d50422e109080c Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 3 Apr 2022 13:32:34 +0200 Subject: [PATCH 3/3] Update safety comments, make `split_at_mut` unsafe `&mut [T]` implies validity which automatically makes `ptr::add` ok within its bounds. But `*mut [T]` does not. Since we still want the benefits of in-bounds pointer arithmetic `split_at_must` must require the caller to pass valid pointers and therefore it is `unsafe`. --- library/core/src/ptr/mut_ptr.rs | 56 ++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index dc63ca809f198..56d6f11ac83ff 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1366,6 +1366,22 @@ impl *mut [T] { /// /// Panics if `mid > len`. /// + /// # Safety + /// + /// `mid` must be [in-bounds] of the underlying [allocated object]. + /// Which means `self` must be dereferenceable and span a single allocation + /// that is at least `mid * size_of::()` bytes long. Not upholding these + /// requirements is *[undefined behavior]* even if the resulting pointers are not used. + /// + /// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the + /// safety requirements of this method are the same as for [`split_at_mut_unchecked`]. + /// The explicit bounds check is only as useful as `len` is correct. + /// + /// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked + /// [in-bounds]: #method.add + /// [allocated object]: crate::ptr#allocated-object + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// /// # Examples /// /// ``` @@ -1374,8 +1390,8 @@ impl *mut [T] { /// /// let mut v = [1, 0, 3, 0, 5, 6]; /// let ptr = &mut v as *mut [_]; - /// let (left, right) = ptr.split_at_mut(2); /// unsafe { + /// let (left, right) = ptr.split_at_mut(2); /// assert_eq!(&*left, [1, 0]); /// assert_eq!(&*right, [3, 0, 5, 6]); /// } @@ -1383,10 +1399,10 @@ impl *mut [T] { #[inline(always)] #[track_caller] #[unstable(feature = "raw_slice_split", issue = "95595")] - pub fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) { + pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) { assert!(mid <= self.len()); - // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. + // SAFETY: The assert above is only a safety-net as long as `self.len()` is correct + // The actual safety requirements of this function are the same as for `split_at_mut_unchecked` unsafe { self.split_at_mut_unchecked(mid) } } @@ -1396,16 +1412,15 @@ impl *mut [T] { /// the index `mid` itself) and the second will contain all /// indices from `[mid, len)` (excluding the index `len` itself). /// - /// For a safe alternative see [`split_at_mut`]. - /// - /// [`split_at_mut`]: #method.split_at_mut - /// /// # Safety /// - /// Calling this method with an out-of-bounds index is *[undefined behavior]* - /// even if the resulting reference is not used. The caller has to ensure that - /// `0 <= mid <= self.len()`. + /// `mid` must be [in-bounds] of the underlying [allocated object]. + /// Which means `self` must be dereferenceable and span a single allocation + /// that is at least `mid * size_of::()` bytes long. Not upholding these + /// requirements is *[undefined behavior]* even if the resulting pointers are not used. /// + /// [in-bounds]: #method.add + /// [out-of-bounds index]: #method.add /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples @@ -1431,16 +1446,12 @@ impl *mut [T] { let len = self.len(); let ptr = self.as_mut_ptr(); - // SAFETY: Caller has to check that `0 <= mid <= self.len()`. - // - // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference - // is fine. - unsafe { - ( - crate::ptr::slice_from_raw_parts_mut(ptr, mid), - crate::ptr::slice_from_raw_parts_mut(ptr.add(mid), len - mid), - ) - } + // SAFETY: Caller must pass a valid pointer and an index that is in-bounds. + let tail = unsafe { ptr.add(mid) }; + ( + crate::ptr::slice_from_raw_parts_mut(ptr, mid), + crate::ptr::slice_from_raw_parts_mut(tail, len - mid), + ) } /// Returns a raw pointer to the slice's buffer. @@ -1466,9 +1477,10 @@ impl *mut [T] { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// - /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// + /// [out-of-bounds index]: #method.add /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples