//! 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::().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 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) { self.iter.size_hint() } #[inline] fn count(self) -> usize { self.iter.count() } #[inline] fn nth(&mut self, n: usize) -> Option { self.iter.nth(n) } #[inline] fn last(self) -> Option { 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.iter.nth_back(n) } } impl ExactSizeIterator for ArrayChunks<'_, T, N> { #[cfg(feature = "unstable")] fn is_empty(&self) -> bool { self.iter.is_empty() } } #[cfg(feature = "unstable")] unsafe impl core::iter::TrustedLen for ArrayChunks<'_, T, N> {} impl 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) { self.iter.size_hint() } #[inline] fn count(self) -> usize { self.iter.count() } #[inline] fn nth(&mut self, n: usize) -> Option { self.iter.nth(n) } #[inline] fn last(self) -> Option { 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.iter.nth_back(n) } } impl ExactSizeIterator for ArrayChunksMut<'_, T, N> { #[cfg(feature = "unstable")] fn is_empty(&self) -> bool { self.iter.is_empty() } } #[cfg(feature = "unstable")] unsafe impl core::iter::TrustedLen for ArrayChunksMut<'_, T, N> {} impl 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 { /// 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(&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(&self) -> ArrayChunks<'_, T, N>; } impl ExtensionTrait for [T] { #[inline] #[cfg_attr(debug_assertions, track_caller)] fn array_chunks_mut(&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(&self) -> ArrayChunks<'_, T, N> { assert!(N != 0, "chunk size must be non-zero"); ArrayChunks::new(self) } }