array_chunks 1.0.0

adds array_chunks back in
Documentation
//! 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)
    }
}