Skip to content

Stabilize slice_as_chunks library feature #139656

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion compiler/rustc_span/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,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)]
Expand Down
1 change: 0 additions & 1 deletion library/core/src/slice/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
127 changes: 106 additions & 21 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1262,6 +1262,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
Expand All @@ -1271,7 +1283,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
Expand All @@ -1286,7 +1297,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]] {
Expand All @@ -1306,15 +1318,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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the section above (which I cannot comment because it is too far from the diff) we need to strike "This check will most probably get changed to a compile time error before this method gets stabilized."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, that had even been mentioned in #74985 (comment) and I forgot.

Did a pass over the docs to fix that bit, elaborate on the resulting lengths, and also add a cross-references between these methods and as_flattened(_mut).

@rustbot ready

///
/// ```
/// #![feature(slice_as_chunks)]
/// let slice = ['l', 'o', 'r', 'e', 'm'];
/// let (chunks, remainder) = slice.as_chunks();
/// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
Expand All @@ -1324,14 +1348,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]
Expand All @@ -1351,21 +1375,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]
Expand Down Expand Up @@ -1418,6 +1455,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
Expand All @@ -1427,7 +1476,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
Expand All @@ -1444,7 +1492,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]] {
Expand All @@ -1464,15 +1513,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;
///
Expand All @@ -1484,7 +1545,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]
Expand All @@ -1504,15 +1566,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;
///
Expand All @@ -1524,7 +1598,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]
Expand Down Expand Up @@ -4810,6 +4885,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`.
Expand Down Expand Up @@ -4850,6 +4930,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`.
Expand Down
3 changes: 1 addition & 2 deletions src/tools/miri/tests/pass/slices.rs
Original file line number Diff line number Diff line change
@@ -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)]

Expand Down Expand Up @@ -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 {
Expand Down
1 change: 0 additions & 1 deletion tests/codegen/slice-as_chunks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Loading