Rollup merge of #139656 - scottmcm:stabilize-slice-as-chunks, r=dtolnay

Stabilize `slice_as_chunks` library feature

~~Draft as this needs #139163 to land first.~~

FCP: https://github.com/rust-lang/rust/issues/74985#issuecomment-2769963395

Methods being stabilized are:
```rust
impl [T] {
    const fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]);
    const fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]);
    const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]];
    const fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]);
    const fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]);
    const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]];
}
```

~~(FCP's not done quite yet, but will in another day if I'm counting right.)~~ FCP Complete: https://github.com/rust-lang/rust/issues/74985#issuecomment-2797951535
This commit is contained in:
Chris Denton
2025-04-28 23:29:15 +00:00
committed by GitHub
6 changed files with 107 additions and 27 deletions

View File

@@ -31,7 +31,6 @@
#![feature(round_char_boundary)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![feature(slice_as_chunks)]
// tidy-alphabetical-end
// The code produced by the `Encodable`/`Decodable` derive macros refer to

View File

@@ -118,7 +118,6 @@
#![feature(ptr_metadata)]
#![feature(set_ptr_value)]
#![feature(slice_as_array)]
#![feature(slice_as_chunks)]
#![feature(slice_ptr_get)]
#![feature(str_internals)]
#![feature(str_split_inclusive_remainder)]

View File

@@ -2335,7 +2335,6 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> {
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
#[rustc_const_unstable(feature = "const_slice_make_iter", issue = "137737")]
// #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
pub(super) const fn new(slice: &'a [T]) -> Self {
let (array_slice, rem) = slice.as_chunks();

View File

@@ -1268,6 +1268,18 @@ impl<T> [T] {
/// Splits the slice into a slice of `N`-element arrays,
/// assuming that there's no remainder.
///
/// This is the inverse operation to [`as_flattened`].
///
/// [`as_flattened`]: slice::as_flattened
///
/// As this is `unsafe`, consider whether you could use [`as_chunks`] or
/// [`as_rchunks`] instead, perhaps via something like
/// `if let (chunks, []) = slice.as_chunks()` or
/// `let (chunks, []) = slice.as_chunks() else { unreachable!() };`.
///
/// [`as_chunks`]: slice::as_chunks
/// [`as_rchunks`]: slice::as_rchunks
///
/// # Safety
///
/// This may only be called when
@@ -1277,7 +1289,6 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(slice_as_chunks)]
/// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
/// let chunks: &[[char; 1]] =
/// // SAFETY: 1-element chunks never have remainder
@@ -1292,7 +1303,8 @@ impl<T> [T] {
/// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
@@ -1312,15 +1324,27 @@ impl<T> [T] {
/// starting at the beginning of the slice,
/// and a remainder slice with length strictly less than `N`.
///
/// The remainder is meaningful in the division sense. Given
/// `let (chunks, remainder) = slice.as_chunks()`, then:
/// - `chunks.len()` equals `slice.len() / N`,
/// - `remainder.len()` equals `slice.len() % N`, and
/// - `slice.len()` equals `chunks.len() * N + remainder.len()`.
///
/// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`].
///
/// [`as_flattened`]: slice::as_flattened
///
/// # Panics
///
/// Panics if `N` is zero. This check will most probably get changed to a compile time
/// error before this method gets stabilized.
/// Panics if `N` is zero.
///
/// Note that this check is against a const generic parameter, not a runtime
/// value, and thus a particular monomorphization will either always panic
/// or it will never panic.
///
/// # Examples
///
/// ```
/// #![feature(slice_as_chunks)]
/// let slice = ['l', 'o', 'r', 'e', 'm'];
/// let (chunks, remainder) = slice.as_chunks();
/// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
@@ -1330,14 +1354,14 @@ impl<T> [T] {
/// If you expect the slice to be an exact multiple, you can combine
/// `let`-`else` with an empty slice pattern:
/// ```
/// #![feature(slice_as_chunks)]
/// let slice = ['R', 'u', 's', 't'];
/// let (chunks, []) = slice.as_chunks::<2>() else {
/// panic!("slice didn't have even length")
/// };
/// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[track_caller]
#[must_use]
@@ -1357,21 +1381,34 @@ impl<T> [T] {
/// starting at the end of the slice,
/// and a remainder slice with length strictly less than `N`.
///
/// The remainder is meaningful in the division sense. Given
/// `let (remainder, chunks) = slice.as_rchunks()`, then:
/// - `remainder.len()` equals `slice.len() % N`,
/// - `chunks.len()` equals `slice.len() / N`, and
/// - `slice.len()` equals `chunks.len() * N + remainder.len()`.
///
/// You can flatten the chunks back into a slice-of-`T` with [`as_flattened`].
///
/// [`as_flattened`]: slice::as_flattened
///
/// # Panics
///
/// Panics if `N` is zero. This check will most probably get changed to a compile time
/// error before this method gets stabilized.
/// Panics if `N` is zero.
///
/// Note that this check is against a const generic parameter, not a runtime
/// value, and thus a particular monomorphization will either always panic
/// or it will never panic.
///
/// # Examples
///
/// ```
/// #![feature(slice_as_chunks)]
/// let slice = ['l', 'o', 'r', 'e', 'm'];
/// let (remainder, chunks) = slice.as_rchunks();
/// assert_eq!(remainder, &['l']);
/// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[track_caller]
#[must_use]
@@ -1424,6 +1461,18 @@ impl<T> [T] {
/// Splits the slice into a slice of `N`-element arrays,
/// assuming that there's no remainder.
///
/// This is the inverse operation to [`as_flattened_mut`].
///
/// [`as_flattened_mut`]: slice::as_flattened_mut
///
/// As this is `unsafe`, consider whether you could use [`as_chunks_mut`] or
/// [`as_rchunks_mut`] instead, perhaps via something like
/// `if let (chunks, []) = slice.as_chunks_mut()` or
/// `let (chunks, []) = slice.as_chunks_mut() else { unreachable!() };`.
///
/// [`as_chunks_mut`]: slice::as_chunks_mut
/// [`as_rchunks_mut`]: slice::as_rchunks_mut
///
/// # Safety
///
/// This may only be called when
@@ -1433,7 +1482,6 @@ impl<T> [T] {
/// # Examples
///
/// ```
/// #![feature(slice_as_chunks)]
/// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!'];
/// let chunks: &mut [[char; 1]] =
/// // SAFETY: 1-element chunks never have remainder
@@ -1450,7 +1498,8 @@ impl<T> [T] {
/// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
@@ -1470,15 +1519,27 @@ impl<T> [T] {
/// starting at the beginning of the slice,
/// and a remainder slice with length strictly less than `N`.
///
/// The remainder is meaningful in the division sense. Given
/// `let (chunks, remainder) = slice.as_chunks_mut()`, then:
/// - `chunks.len()` equals `slice.len() / N`,
/// - `remainder.len()` equals `slice.len() % N`, and
/// - `slice.len()` equals `chunks.len() * N + remainder.len()`.
///
/// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`].
///
/// [`as_flattened_mut`]: slice::as_flattened_mut
///
/// # Panics
///
/// Panics if `N` is zero. This check will most probably get changed to a compile time
/// error before this method gets stabilized.
/// Panics if `N` is zero.
///
/// Note that this check is against a const generic parameter, not a runtime
/// value, and thus a particular monomorphization will either always panic
/// or it will never panic.
///
/// # Examples
///
/// ```
/// #![feature(slice_as_chunks)]
/// let v = &mut [0, 0, 0, 0, 0];
/// let mut count = 1;
///
@@ -1490,7 +1551,8 @@ impl<T> [T] {
/// }
/// assert_eq!(v, &[1, 1, 2, 2, 9]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[track_caller]
#[must_use]
@@ -1510,15 +1572,27 @@ impl<T> [T] {
/// starting at the end of the slice,
/// and a remainder slice with length strictly less than `N`.
///
/// The remainder is meaningful in the division sense. Given
/// `let (remainder, chunks) = slice.as_rchunks_mut()`, then:
/// - `remainder.len()` equals `slice.len() % N`,
/// - `chunks.len()` equals `slice.len() / N`, and
/// - `slice.len()` equals `chunks.len() * N + remainder.len()`.
///
/// You can flatten the chunks back into a slice-of-`T` with [`as_flattened_mut`].
///
/// [`as_flattened_mut`]: slice::as_flattened_mut
///
/// # Panics
///
/// Panics if `N` is zero. This check will most probably get changed to a compile time
/// error before this method gets stabilized.
/// Panics if `N` is zero.
///
/// Note that this check is against a const generic parameter, not a runtime
/// value, and thus a particular monomorphization will either always panic
/// or it will never panic.
///
/// # Examples
///
/// ```
/// #![feature(slice_as_chunks)]
/// let v = &mut [0, 0, 0, 0, 0];
/// let mut count = 1;
///
@@ -1530,7 +1604,8 @@ impl<T> [T] {
/// }
/// assert_eq!(v, &[9, 1, 1, 2, 2]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
#[stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "slice_as_chunks", since = "CURRENT_RUSTC_VERSION")]
#[inline]
#[track_caller]
#[must_use]
@@ -4816,6 +4891,11 @@ impl<T> [MaybeUninit<T>] {
impl<T, const N: usize> [[T; N]] {
/// Takes a `&[[T; N]]`, and flattens it to a `&[T]`.
///
/// For the opposite operation, see [`as_chunks`] and [`as_rchunks`].
///
/// [`as_chunks`]: slice::as_chunks
/// [`as_rchunks`]: slice::as_rchunks
///
/// # Panics
///
/// This panics if the length of the resulting slice would overflow a `usize`.
@@ -4856,6 +4936,11 @@ impl<T, const N: usize> [[T; N]] {
/// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`.
///
/// For the opposite operation, see [`as_chunks_mut`] and [`as_rchunks_mut`].
///
/// [`as_chunks_mut`]: slice::as_chunks_mut
/// [`as_rchunks_mut`]: slice::as_rchunks_mut
///
/// # Panics
///
/// This panics if the length of the resulting slice would overflow a `usize`.

View File

@@ -1,7 +1,6 @@
//@revisions: stack tree
//@[tree]compile-flags: -Zmiri-tree-borrows
//@compile-flags: -Zmiri-strict-provenance
#![feature(slice_as_chunks)]
#![feature(slice_partition_dedup)]
#![feature(layout_for_ptr)]
@@ -227,7 +226,7 @@ fn test_for_invalidated_pointers() {
buffer.reverse();
// Calls `fn as_chunks_unchecked_mut` internally (requires unstable `#![feature(slice_as_chunks)]`):
// Calls `fn as_chunks_unchecked_mut` internally:
assert_eq!(2, buffer.as_chunks_mut::<32>().0.len());
for chunk in buffer.as_chunks_mut::<32>().0 {
for elem in chunk {

View File

@@ -2,7 +2,6 @@
//@ only-64bit (because the LLVM type of i64 for usize shows up)
#![crate_type = "lib"]
#![feature(slice_as_chunks)]
// CHECK-LABEL: @chunks4
#[no_mangle]