diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-01-19 19:26:59 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-19 19:26:59 +0100 |
| commit | 64461dab0185a3c42be7ceb0038a7574f0f062d8 (patch) | |
| tree | e10d04c58087235d321e3e9a913e5d563482ee90 | |
| parent | 32ec40c68533f325a3c8fe787b77ef5c9e209b23 (diff) | |
| parent | 500d6f64791d4f9576c8588ef2cdeab4a3139a02 (diff) | |
| download | rust-64461dab0185a3c42be7ceb0038a7574f0f062d8.tar.gz rust-64461dab0185a3c42be7ceb0038a7574f0f062d8.zip | |
Rollup merge of #117561 - tgross35:split-array, r=scottmcm
Stabilize `slice_first_last_chunk`
This PR does a few different things based around stabilizing `slice_first_last_chunk`. They are split up so this PR can be by-commit reviewed, I can move parts to a separate PR if desired.
This feature provides a very elegant API to extract arrays from either end of a slice, such as for parsing integers from binary data.
## Stabilize `slice_first_last_chunk`
ACP: https://github.com/rust-lang/libs-team/issues/69
Implementation: https://github.com/rust-lang/rust/issues/90091
Tracking issue: https://github.com/rust-lang/rust/issues/111774
This stabilizes the functionality from https://github.com/rust-lang/rust/issues/111774:
```rust
impl [T] {
pub const fn first_chunk<const N: usize>(&self) -> Option<&[T; N]>;
pub fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]>;
pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]>;
pub fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]>;
pub const fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])>;
pub fn split_first_chunk_mut<const N: usize>(&mut self) -> Option<(&mut [T; N], &mut [T])>;
pub const fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])>;
pub fn split_last_chunk_mut<const N: usize>(&mut self) -> Option<(&mut [T], &mut [T; N])>;
}
```
Const stabilization is included for all non-mut methods, which are blocked on `const_mut_refs`. This change includes marking the trivial function `slice_split_at_unchecked` const-stable for internal use (but not fully stable).
## Remove `split_array` slice methods
Tracking issue: https://github.com/rust-lang/rust/issues/90091
Implementation: https://github.com/rust-lang/rust/pull/83233#pullrequestreview-780315524
This PR also removes the following unstable methods from the `split_array` feature, https://github.com/rust-lang/rust/issues/90091:
```rust
impl<T> [T] {
pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]);
pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]);
pub fn rsplit_array_ref<const N: usize>(&self) -> (&[T], &[T; N]);
pub fn rsplit_array_mut<const N: usize>(&mut self) -> (&mut [T], &mut [T; N]);
}
```
This is done because discussion at #90091 and its implementation PR indicate a strong preference for nonpanicking APIs that return `Option`. The only difference between functions under the `split_array` and `slice_first_last_chunk` features is `Option` vs. panic, so remove the duplicates as part of this stabilization.
This does not affect the array methods from `split_array`. We will want to revisit these once `generic_const_exprs` is further along.
## Reverse order of return tuple for `split_last_chunk{,_mut}`
An unresolved question for #111774 is whether to return `(preceding_slice, last_chunk)` (`(&[T], &[T; N])`) or the reverse (`(&[T; N], &[T])`), from `split_last_chunk` and `split_last_chunk_mut`. It is currently implemented as `(last_chunk, preceding_slice)` which matches `split_last -> (&T, &[T])`. The first commit changes these to `(&[T], &[T; N])` for these reasons:
- More consistent with other splitting methods that return multiple values: `str::rsplit_once`, `slice::split_at{,_mut}`, `slice::align_to` all return tuples with the items in order
- More intuitive (arguably opinion, but it is consistent with other language elements like pattern matching `let [a, b, rest @ ..] ...`
- If we ever added a varidic way to obtain multiple chunks, it would likely return something in order: `.split_many_last::<(2, 4)>() -> (&[T], &[T; 2], &[T; 4])`
- It is the ordering used in the `rsplit_array` methods
I think the inconsistency with `split_last` could be acceptable in this case, since for `split_last` the scalar `&T` doesn't have any internal order to maintain with the other items.
## Unresolved questions
Do we want to reserve the same names on `[u8; N]` to avoid inference confusion? https://github.com/rust-lang/rust/pull/117561#issuecomment-1793388647
---
`slice_first_last_chunk` has only been around since early 2023, but `split_array` has been around since 2021.
`@rustbot` label -T-libs +T-libs-api -T-libs +needs-fcp
cc `@rust-lang/wg-const-eval,` `@scottmcm` who raised this topic, `@clarfonthey` implementer of `slice_first_last_chunk` `@jethrogb` implementer of `split_array`
Zulip discussion: https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/Stabilizing.20array-from-slice.20*something*.3F
Fixes: #111774
| -rw-r--r-- | compiler/rustc_serialize/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/array/mod.rs | 8 | ||||
| -rw-r--r-- | library/core/src/slice/mod.rs | 290 | ||||
| -rw-r--r-- | library/core/tests/slice.rs | 52 |
4 files changed, 90 insertions, 261 deletions
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 35275821453..48bee4cd2f0 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -16,7 +16,6 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(ptr_sub_ptr)] -#![feature(slice_first_last_chunk)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 34213637a32..9d95b32409c 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -647,7 +647,7 @@ impl<T, const N: usize> [T; N] { )] #[inline] pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T]) { - (&self[..]).split_array_ref::<M>() + (&self[..]).split_first_chunk::<M>().unwrap() } /// Divides one mutable array reference into two at an index. @@ -680,7 +680,7 @@ impl<T, const N: usize> [T; N] { )] #[inline] pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) { - (&mut self[..]).split_array_mut::<M>() + (&mut self[..]).split_first_chunk_mut::<M>().unwrap() } /// Divides one array reference into two at an index from the end. @@ -725,7 +725,7 @@ impl<T, const N: usize> [T; N] { )] #[inline] pub fn rsplit_array_ref<const M: usize>(&self) -> (&[T], &[T; M]) { - (&self[..]).rsplit_array_ref::<M>() + (&self[..]).split_last_chunk::<M>().unwrap() } /// Divides one mutable array reference into two at an index from the end. @@ -758,7 +758,7 @@ impl<T, const N: usize> [T; N] { )] #[inline] pub fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T], &mut [T; M]) { - (&mut self[..]).rsplit_array_mut::<M>() + (&mut self[..]).split_last_chunk_mut::<M>().unwrap() } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5edc89e4cb5..ee36d93576b 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -296,7 +296,7 @@ impl<T> [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns a mutable pointer to the last item in the slice. + /// Returns a mutable reference to the last item in the slice. /// /// # Examples /// @@ -316,13 +316,13 @@ impl<T> [T] { if let [.., last] = self { Some(last) } else { None } } - /// Returns the first `N` elements of the slice, or `None` if it has fewer than `N` elements. + /// Return an array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let u = [10, 40, 30]; /// assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); /// @@ -332,27 +332,26 @@ impl<T> [T] { /// let w: &[i32] = &[]; /// assert_eq!(Some(&[]), w.first_chunk::<0>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn first_chunk<const N: usize>(&self) -> Option<&[T; N]> { if self.len() < N { None } else { // SAFETY: We explicitly check for the correct number of elements, // and do not let the reference outlive the slice. - Some(unsafe { &*(self.as_ptr() as *const [T; N]) }) + Some(unsafe { &*(self.as_ptr().cast::<[T; N]>()) }) } } - /// Returns a mutable reference to the first `N` elements of the slice, - /// or `None` if it has fewer than `N` elements. + /// Return a mutable array reference to the first `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some(first) = x.first_chunk_mut::<2>() { @@ -360,10 +359,12 @@ impl<T> [T] { /// first[1] = 4; /// } /// assert_eq!(x, &[5, 4, 2]); + /// + /// assert_eq!(None, x.first_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -371,28 +372,29 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(self.as_mut_ptr() as *mut [T; N]) }) + Some(unsafe { &mut *(self.as_mut_ptr().cast::<[T; N]>()) }) } } - /// Returns the first `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return an array reference to the first `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &[0, 1, 2]; /// /// if let Some((first, elements)) = x.split_first_chunk::<2>() { /// assert_eq!(first, &[0, 1]); /// assert_eq!(elements, &[2]); /// } + /// + /// assert_eq!(None, x.split_first_chunk::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] pub const fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])> { if self.len() < N { None @@ -402,18 +404,18 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(first.as_ptr() as *const [T; N]) }, tail)) + Some((unsafe { &*(first.as_ptr().cast::<[T; N]>()) }, tail)) } } - /// Returns a mutable reference to the first `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return a mutable array reference to the first `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some((first, elements)) = x.split_first_chunk_mut::<2>() { @@ -422,10 +424,12 @@ impl<T> [T] { /// elements[0] = 5; /// } /// assert_eq!(x, &[3, 4, 5]); + /// + /// assert_eq!(None, x.split_first_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn split_first_chunk_mut<const N: usize>( &mut self, ) -> Option<(&mut [T; N], &mut [T])> { @@ -438,29 +442,30 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(first.as_mut_ptr() as *mut [T; N]) }, tail)) + Some((unsafe { &mut *(first.as_mut_ptr().cast::<[T; N]>()) }, tail)) } } - /// Returns the last `N` elements of the slice and the remainder, - /// or `None` if it has fewer than `N` elements. + /// Return an array reference to the last `N` items in the slice and the remaining slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &[0, 1, 2]; /// - /// if let Some((last, elements)) = x.split_last_chunk::<2>() { - /// assert_eq!(last, &[1, 2]); + /// if let Some((elements, last)) = x.split_last_chunk::<2>() { /// assert_eq!(elements, &[0]); + /// assert_eq!(last, &[1, 2]); /// } + /// + /// assert_eq!(None, x.split_last_chunk::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] - pub const fn split_last_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])> { + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + pub const fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])> { if self.len() < N { None } else { @@ -469,32 +474,35 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some((unsafe { &*(last.as_ptr() as *const [T; N]) }, init)) + Some((init, unsafe { &*(last.as_ptr().cast::<[T; N]>()) })) } } - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// Return a mutable array reference to the last `N` items in the slice and the remaining + /// slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// - /// if let Some((last, elements)) = x.split_last_chunk_mut::<2>() { + /// if let Some((elements, last)) = x.split_last_chunk_mut::<2>() { /// last[0] = 3; /// last[1] = 4; /// elements[0] = 5; /// } /// assert_eq!(x, &[5, 3, 4]); + /// + /// assert_eq!(None, x.split_last_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn split_last_chunk_mut<const N: usize>( &mut self, - ) -> Option<(&mut [T; N], &mut [T])> { + ) -> Option<(&mut [T], &mut [T; N])> { if self.len() < N { None } else { @@ -504,17 +512,17 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and enforce exclusive mutability of the chunk by the split. - Some((unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }, init)) + Some((init, unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) })) } } - /// Returns the last element of the slice, or `None` if it is empty. + /// Return an array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let u = [10, 40, 30]; /// assert_eq!(Some(&[40, 30]), u.last_chunk::<2>()); /// @@ -524,9 +532,9 @@ impl<T> [T] { /// let w: &[i32] = &[]; /// assert_eq!(Some(&[]), w.last_chunk::<0>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn last_chunk<const N: usize>(&self) -> Option<&[T; N]> { if self.len() < N { None @@ -537,17 +545,17 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // and do not let the references outlive the slice. - Some(unsafe { &*(last.as_ptr() as *const [T; N]) }) + Some(unsafe { &*(last.as_ptr().cast::<[T; N]>()) }) } } - /// Returns a mutable pointer to the last item in the slice. + /// Return a mutable array reference to the last `N` items in the slice. + /// + /// If the slice is not at least `N` in length, this will return `None`. /// /// # Examples /// /// ``` - /// #![feature(slice_first_last_chunk)] - /// /// let x = &mut [0, 1, 2]; /// /// if let Some(last) = x.last_chunk_mut::<2>() { @@ -555,10 +563,12 @@ impl<T> [T] { /// last[1] = 20; /// } /// assert_eq!(x, &[0, 10, 20]); + /// + /// assert_eq!(None, x.last_chunk_mut::<4>()); /// ``` - #[unstable(feature = "slice_first_last_chunk", issue = "111774")] - #[rustc_const_unstable(feature = "slice_first_last_chunk", issue = "111774")] #[inline] + #[stable(feature = "slice_first_last_chunk", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] pub const fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]> { if self.len() < N { None @@ -570,7 +580,7 @@ impl<T> [T] { // SAFETY: We explicitly check for the correct number of elements, // do not let the reference outlive the slice, // and require exclusive access to the entire slice to mutate the chunk. - Some(unsafe { &mut *(last.as_mut_ptr() as *mut [T; N]) }) + Some(unsafe { &mut *(last.as_mut_ptr().cast::<[T; N]>()) }) } } @@ -1859,7 +1869,6 @@ impl<T> [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")] - #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)] #[inline] #[track_caller] #[must_use] @@ -1946,7 +1955,10 @@ impl<T> [T] { /// } /// ``` #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] - #[rustc_const_unstable(feature = "slice_split_at_unchecked", issue = "76014")] + #[rustc_const_stable( + feature = "const_slice_split_at_unchecked", + since = "CURRENT_RUSTC_VERSION" + )] #[inline] #[must_use] pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T]) { @@ -2019,164 +2031,6 @@ impl<T> [T] { unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } - /// Divides one slice into an array and a remainder slice at an index. - /// - /// The array will contain all indices from `[0, N)` (excluding - /// the index `N` itself) and the slice will contain all - /// indices from `[N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let v = &[1, 2, 3, 4, 5, 6][..]; - /// - /// { - /// let (left, right) = v.split_array_ref::<0>(); - /// assert_eq!(left, &[]); - /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_array_ref::<2>(); - /// assert_eq!(left, &[1, 2]); - /// assert_eq!(right, [3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_array_ref::<6>(); - /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, []); - /// } - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[track_caller] - #[must_use] - pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) { - let (a, b) = self.split_at(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (&*(a.as_ptr() as *const [T; N]), b) } - } - - /// Divides one mutable slice into an array and a remainder slice at an index. - /// - /// The array will contain all indices from `[0, N)` (excluding - /// the index `N` itself) and the slice will contain all - /// indices from `[N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.split_array_mut::<2>(); - /// assert_eq!(left, &mut [1, 0]); - /// assert_eq!(right, [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[track_caller] - #[must_use] - pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) { - let (a, b) = self.split_at_mut(N); - // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) } - } - - /// Divides one slice into an array and a remainder slice at an index from - /// the end. - /// - /// The slice will contain all indices from `[0, len - N)` (excluding - /// the index `len - N` itself) and the array will contain all - /// indices from `[len - N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let v = &[1, 2, 3, 4, 5, 6][..]; - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<0>(); - /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); - /// assert_eq!(right, &[]); - /// } - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<2>(); - /// assert_eq!(left, [1, 2, 3, 4]); - /// assert_eq!(right, &[5, 6]); - /// } - /// - /// { - /// let (left, right) = v.rsplit_array_ref::<6>(); - /// assert_eq!(left, []); - /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]); - /// } - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[must_use] - pub fn rsplit_array_ref<const N: usize>(&self) -> (&[T], &[T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at) - unsafe { (a, &*(b.as_ptr() as *const [T; N])) } - } - - /// Divides one mutable slice into an array and a remainder slice at an - /// index from the end. - /// - /// The slice will contain all indices from `[0, len - N)` (excluding - /// the index `N` itself) and the array will contain all - /// indices from `[len - N, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `N > len`. - /// - /// # Examples - /// - /// ``` - /// #![feature(split_array)] - /// - /// let mut v = &mut [1, 0, 3, 0, 5, 6][..]; - /// let (left, right) = v.rsplit_array_mut::<4>(); - /// assert_eq!(left, [1, 0]); - /// assert_eq!(right, &mut [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); - /// ``` - #[unstable(feature = "split_array", reason = "new API", issue = "90091")] - #[inline] - #[must_use] - pub fn rsplit_array_mut<const N: usize>(&mut self) -> (&mut [T], &mut [T; N]) { - assert!(N <= self.len()); - let (a, b) = self.split_at_mut(self.len() - N); - // SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut) - unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) } - } - /// Returns an iterator over subslices separated by elements that match /// `pred`. The matched element is not contained in the subslices. /// diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index cc1fc7e4d7e..c7a5feb04ae 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2398,37 +2398,45 @@ mod swap_panics { } #[test] -fn slice_split_array_mut() { +fn slice_split_first_chunk_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.split_array_mut::<0>(); + let (left, right) = v.split_first_chunk_mut::<0>().unwrap(); assert_eq!(left, &mut []); assert_eq!(right, [1, 2, 3, 4, 5, 6]); } { - let (left, right) = v.split_array_mut::<6>(); + let (left, right) = v.split_first_chunk_mut::<6>().unwrap(); assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]); assert_eq!(right, []); } + + { + assert!(v.split_first_chunk_mut::<7>().is_none()); + } } #[test] -fn slice_rsplit_array_mut() { +fn slice_split_last_chunk_mut() { let v = &mut [1, 2, 3, 4, 5, 6][..]; { - let (left, right) = v.rsplit_array_mut::<0>(); + let (left, right) = v.split_last_chunk_mut::<0>().unwrap(); assert_eq!(left, [1, 2, 3, 4, 5, 6]); assert_eq!(right, &mut []); } { - let (left, right) = v.rsplit_array_mut::<6>(); + let (left, right) = v.split_last_chunk_mut::<6>().unwrap(); assert_eq!(left, []); assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]); } + + { + assert!(v.split_last_chunk_mut::<7>().is_none()); + } } #[test] @@ -2443,38 +2451,6 @@ fn split_as_slice() { assert_eq!(split.as_slice(), &[]); } -#[should_panic] -#[test] -fn slice_split_array_ref_out_of_bounds() { - let v = &[1, 2, 3, 4, 5, 6][..]; - - let _ = v.split_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn slice_split_array_mut_out_of_bounds() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - let _ = v.split_array_mut::<7>(); -} - -#[should_panic] -#[test] -fn slice_rsplit_array_ref_out_of_bounds() { - let v = &[1, 2, 3, 4, 5, 6][..]; - - let _ = v.rsplit_array_ref::<7>(); -} - -#[should_panic] -#[test] -fn slice_rsplit_array_mut_out_of_bounds() { - let v = &mut [1, 2, 3, 4, 5, 6][..]; - - let _ = v.rsplit_array_mut::<7>(); -} - #[test] fn slice_split_once() { let v = &[1, 2, 3, 2, 4][..]; |
