adds array_chunks back, after it was taken from us
Diffstat (limited to 'src/lib.rs')
| -rw-r--r-- | src/lib.rs | 335 |
1 files changed, 335 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d593d5a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,335 @@ +//! Adds `array_chunks` on stable. +//! This used to be a nightly feature, now its a crate. +//! +//! This is just a wrapper so you dont have to write `x.as_chunks::<N>().0.into_iter()`. +#![allow(unstable_name_collisions)] +#![cfg_attr( + feature = "unstable", + feature( + trusted_len, + trusted_random_access, + min_specialization, + exact_size_is_empty + ) +)] +#![no_std] +use core::{iter::FusedIterator, slice::IterMut}; + +/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`remainder`](ArrayChunks::remainder) function from the iterator. +/// +/// This struct is created by the [`ExtensionTrait::array_chunks`] method. +/// +/// # Example +/// +/// ``` +/// use array_chunks::*; +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let mut iter = slice.array_chunks::<2>(); +/// assert_eq!(iter.next(), Some(&['l', 'o'])); +/// assert_eq!(iter.next(), Some(&['r', 'e'])); +/// assert_eq!(iter.next(), None); +/// ``` +#[derive(Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ArrayChunks<'a, T: 'a, const N: usize> { + iter: core::slice::Iter<'a, [T; N]>, + rem: &'a [T], +} + +impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + pub fn new(slice: &'a [T]) -> Self { + let (array_slice, rem) = slice.as_chunks(); + Self { + iter: array_slice.iter(), + rem, + } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[must_use] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> { + fn clone(&self) -> Self { + ArrayChunks { + iter: self.iter.clone(), + rem: self.rem, + } + } +} + +impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option<Self::Item> { + self.iter.last() + } + #[cfg(feature = "unstable")] + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are + // transferred to the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } + } +} + +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + self.iter.nth_back(n) + } +} + +impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> { + #[cfg(feature = "unstable")] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} +#[cfg(feature = "unstable")] +unsafe impl<T, const N: usize> core::iter::TrustedLen for ArrayChunks<'_, T, N> {} + +impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {} + +#[doc(hidden)] +#[cfg(feature = "unstable")] +unsafe impl<'a, T, const N: usize> core::iter::TrustedRandomAccess for ArrayChunks<'a, T, N> {} + +#[doc(hidden)] +#[cfg(feature = "unstable")] +unsafe impl<'a, T, const N: usize> core::iter::TrustedRandomAccessNoCoerce + for ArrayChunks<'a, T, N> +{ + const MAY_HAVE_SIDE_EFFECT: bool = false; +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements +/// at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`into_remainder`](ArrayChunksMut::into_remainder) function from the iterator. +/// +/// This struct is created by the [`array_chunks_mut`](ExtensionTrait::array_chunks_mut) method. +/// +/// # Example +/// +/// ``` +/// use array_chunks::*; +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks_mut::<2>(); +/// ``` +#[derive(Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { + iter: IterMut<'a, [T; N]>, + rem: &'a mut [T], +} + +impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + pub fn new(slice: &'a mut [T]) -> Self { + let (array_slice, rem) = slice.as_chunks_mut(); + Self { + iter: array_slice.iter_mut(), + rem, + } + } + + /// Returns the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `N-1` + /// elements. + #[must_use = "`self` will be dropped if the result is not used"] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { + type Item = &'a mut [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<Self::Item> { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option<Self::Item> { + self.iter.last() + } + #[cfg(feature = "unstable")] + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to + // the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } + } +} + +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<Self::Item> { + self.iter.nth_back(n) + } +} + +impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> { + #[cfg(feature = "unstable")] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} +#[cfg(feature = "unstable")] +unsafe impl<T, const N: usize> core::iter::TrustedLen for ArrayChunksMut<'_, T, N> {} + +impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {} + +#[doc(hidden)] +#[cfg(feature = "unstable")] +unsafe impl<'a, T, const N: usize> core::iter::TrustedRandomAccess for ArrayChunksMut<'a, T, N> {} + +#[doc(hidden)] +#[cfg(feature = "unstable")] +unsafe impl<'a, T, const N: usize> core::iter::TrustedRandomAccessNoCoerce + for ArrayChunksMut<'a, T, N> +{ + const MAY_HAVE_SIDE_EFFECT: bool = false; +} + +/// Extension trait to call [`ArrayChunks::new`] and [`ArrayChunksMut::new`] on slices. +pub trait ExtensionTrait<T> { + /// Returns an iterator over `N` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable array references and do not overlap. If `N` does not divide + /// the length of the slice, then the last up to `N-1` elements will be omitted and + /// can be retrieved from the `into_remainder` function of the iterator. + /// + /// This method is the const generic equivalent of [`chunks_exact_mut`]. + /// + /// # Panics + /// + /// Panics if `N` is 0. + /// + /// # Examples + /// + /// ``` + /// use array_chunks::*; + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.array_chunks_mut() { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_exact_mut`]: slice::chunks_exact_mut + + #[track_caller] + fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N>; + + /// Returns an iterator over `N` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are array references and do not overlap. If `N` does not divide the + /// length of the slice, then the last up to `N-1` elements will be omitted and can be + /// retrieved from the `remainder` function of the iterator. + /// + /// This method is the const generic equivalent of [`chunks_exact`]. + /// + /// # Panics + /// + /// Panics if `N` is 0. + /// + /// # Examples + /// + /// ``` + /// use array_chunks::*; + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.array_chunks(); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// assert_eq!(iter.remainder(), &['m']); + /// ``` + /// + /// [`chunks_exact`]: slice::chunks_exact + + #[track_caller] + fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N>; +} + +impl<T> ExtensionTrait<T> for [T] { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N> { + assert!(N != 0, "chunk size must be non-zero"); + ArrayChunksMut::new(self) + } + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> { + assert!(N != 0, "chunk size must be non-zero"); + ArrayChunks::new(self) + } +} |