adds array_chunks back, after it was taken from us
-rw-r--r--.gitignore1
-rw-r--r--Cargo.toml14
-rw-r--r--LICENSE21
-rw-r--r--README.md15
-rw-r--r--src/lib.rs335
5 files changed, 386 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..03314f7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+Cargo.lock
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..847444b
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "array_chunks"
+version = "1.0.0"
+edition = "2021"
+description = "adds array_chunks back in"
+authors = ["bend-n <[email protected]>"]
+license = "MIT"
+repository = "https://github.com/bend-n/atools"
+keywords = ["array"]
+categories = ["no-std"]
+rust-version = "1.88.0"
+
+[features]
+unstable = []
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bf3f588
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 bendn
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d996b89
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+### After array_chunks was brutally taken from us in [#143289](https://github.com/rust-lang/rust/pull/143289/files), I have taken it upon myself to diligently add it back to rust.
+
+![rust 1.88.0](https://img.shields.io/badge/rust-1.88.0-blue?style=for-the-badge&logo=rust&logoColor=white)
+![rust stable](https://img.shields.io/badge/stable-green?style=for-the-badge&logo=rust&logoColor=white)
+
+An iterator over a slice in (non-overlapping) chunks (`N` elements at a time), starting at the beginning of the slice.
+
+```rust
+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);
+```
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)
+ }
+}