Skip to content

Commit 652f34d

Browse files
committed
Add [T]::as_chunks_mut (as unstable)
Allows getting the slices directly, rather than just through an iterator as in `array_chunks(_mut)`. The constructors for those iterators are then written in terms of these methods, so the iterator constructors no longer have any `unsafe` of their own.
1 parent 4ccf5f7 commit 652f34d

File tree

2 files changed

+71
-15
lines changed

2 files changed

+71
-15
lines changed

library/core/src/slice/iter.rs

+4-15
Original file line numberDiff line numberDiff line change
@@ -2102,13 +2102,8 @@ pub struct ArrayChunks<'a, T: 'a, const N: usize> {
21022102
impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
21032103
#[inline]
21042104
pub(super) fn new(slice: &'a [T]) -> Self {
2105-
let len = slice.len() / N;
2106-
let (fst, snd) = slice.split_at(len * N);
2107-
// SAFETY: We cast a slice of `len * N` elements into
2108-
// a slice of `len` many `N` elements chunks.
2109-
let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) };
2110-
2111-
Self { iter: array_slice.iter(), rem: snd }
2105+
let (array_slice, rem) = slice.as_chunks();
2106+
Self { iter: array_slice.iter(), rem }
21122107
}
21132108

21142109
/// Returns the remainder of the original slice that is not going to be
@@ -2229,14 +2224,8 @@ pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
22292224
impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
22302225
#[inline]
22312226
pub(super) fn new(slice: &'a mut [T]) -> Self {
2232-
let len = slice.len() / N;
2233-
let (fst, snd) = slice.split_at_mut(len * N);
2234-
// SAFETY: We cast a slice of `len * N` elements into
2235-
// a slice of `len` many `N` elements chunks.
2236-
unsafe {
2237-
let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len);
2238-
Self { iter: array_slice.iter_mut(), rem: snd }
2239-
}
2227+
let (array_slice, rem) = slice.as_chunks_mut();
2228+
Self { iter: array_slice.iter_mut(), rem }
22402229
}
22412230

22422231
/// Returns the remainder of the original slice that is not going to be

library/core/src/slice/mod.rs

+67
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,36 @@ impl<T> [T] {
883883
ChunksExactMut::new(self, chunk_size)
884884
}
885885

886+
/// Splits the slice into a slice of `N`-element arrays,
887+
/// starting at the beginning of the slice,
888+
/// and a remainder slice with length strictly less than `N`.
889+
///
890+
/// # Panics
891+
///
892+
/// Panics if `N` is 0. This check will most probably get changed to a compile time
893+
/// error before this method gets stabilized.
894+
///
895+
/// # Examples
896+
///
897+
/// ```
898+
/// #![feature(slice_as_chunks)]
899+
/// let slice = ['l', 'o', 'r', 'e', 'm'];
900+
/// let (chunks, remainder) = slice.as_chunks();
901+
/// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
902+
/// assert_eq!(remainder, &['m']);
903+
/// ```
904+
#[unstable(feature = "slice_as_chunks", issue = "74985")]
905+
#[inline]
906+
pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {
907+
assert_ne!(N, 0);
908+
let len = self.len() / N;
909+
let (multiple_of_n, remainder) = self.split_at(len * N);
910+
// SAFETY: We cast a slice of `len * N` elements into
911+
// a slice of `len` many `N` elements chunks.
912+
let array_slice: &[[T; N]] = unsafe { from_raw_parts(multiple_of_n.as_ptr().cast(), len) };
913+
(array_slice, remainder)
914+
}
915+
886916
/// Returns an iterator over `N` elements of the slice at a time, starting at the
887917
/// beginning of the slice.
888918
///
@@ -917,6 +947,43 @@ impl<T> [T] {
917947
ArrayChunks::new(self)
918948
}
919949

950+
/// Splits the slice into a slice of `N`-element arrays,
951+
/// starting at the beginning of the slice,
952+
/// and a remainder slice with length strictly less than `N`.
953+
///
954+
/// # Panics
955+
///
956+
/// Panics if `N` is 0. This check will most probably get changed to a compile time
957+
/// error before this method gets stabilized.
958+
///
959+
/// # Examples
960+
///
961+
/// ```
962+
/// #![feature(slice_as_chunks)]
963+
/// let v = &mut [0, 0, 0, 0, 0];
964+
/// let mut count = 1;
965+
///
966+
/// let (chunks, remainder) = v.as_chunks_mut();
967+
/// remainder[0] = 9;
968+
/// for chunk in chunks {
969+
/// *chunk = [count; 2];
970+
/// count += 1;
971+
/// }
972+
/// assert_eq!(v, &[1, 1, 2, 2, 9]);
973+
/// ```
974+
#[unstable(feature = "slice_as_chunks", issue = "74985")]
975+
#[inline]
976+
pub fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) {
977+
assert_ne!(N, 0);
978+
let len = self.len() / N;
979+
let (multiple_of_n, remainder) = self.split_at_mut(len * N);
980+
let array_slice: &mut [[T; N]] =
981+
// SAFETY: We cast a slice of `len * N` elements into
982+
// a slice of `len` many `N` elements chunks.
983+
unsafe { from_raw_parts_mut(multiple_of_n.as_mut_ptr().cast(), len) };
984+
(array_slice, remainder)
985+
}
986+
920987
/// Returns an iterator over `N` elements of the slice at a time, starting at the
921988
/// beginning of the slice.
922989
///

0 commit comments

Comments
 (0)