Skip to content

Instantly share code, notes, and snippets.

@jirutka
Last active January 5, 2023 16:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jirutka/f9ec89f9aa8ac749b92b1a857a630d08 to your computer and use it in GitHub Desktop.
Save jirutka/f9ec89f9aa8ac749b92b1a857a630d08 to your computer and use it in GitHub Desktop.
Iterator::array_chunks for stable Rust 1.66
pub(crate) struct ChunksExact<const N: usize, I> {
iter: I,
}
impl<const N: usize, I: Iterator<Item = T>, T> Iterator for ChunksExact<N, I> {
type Item = [T; N];
fn next(&mut self) -> Option<Self::Item> {
assert_ne!(N, 0);
let mut vec: Vec<T> = Vec::with_capacity(N);
for _ in 0..N {
match self.iter.next() {
Some(item) => vec.push(item),
None => return None,
}
}
let ary: [T; N] = vec.try_into().unwrap_or_else(|v: Vec<T>| {
panic!("Expected a Vec of length {} but it was {}", N, v.len())
});
Some(ary)
}
}
pub(crate) trait ChunksExactIterator: Sized {
/// Returns an iterator over `N` elements of the iterator at a time.
///
/// This is a custom implementation of [Iterator::array_chunks] for stable
/// Rust 1.66, but for simplicity without
/// [`.into_remainder()`][std::iter::adapters::ArrayChunks].
///
/// # Panics
///
/// Panics if `N` is 0.
///
/// # Examples
///
/// ```
/// let mut iter = "lorem".chars().array_chunks();
/// assert_eq!(iter.next(), Some(['l', 'o']));
/// assert_eq!(iter.next(), Some(['r', 'e']));
/// assert_eq!(iter.next(), None);
/// ```
///
/// TODO: Remove it after `iter_array_chunks` is stabilized.
/// https://github.com/rust-lang/rust/issues/100450
fn chunks_exact<const N: usize>(self) -> ChunksExact<N, Self>;
}
impl<I: Iterator> ChunksExactIterator for I {
fn chunks_exact<const N: usize>(self) -> ChunksExact<N, Self> {
assert!(N != 0, "chunk size must be non-zero");
ChunksExact { iter: self }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn chunks_exact_with_divisible_input() {
let actual = ["a", "b", "c", "d"]
.into_iter()
.chunks_exact()
.collect::<Vec<[&str; 2]>>();
assert_eq!(actual, vec![["a", "b"], ["c", "d"]]);
}
#[test]
fn chunks_exact_with_indivisible_input() {
let actual = ["a", "b", "c", "d"]
.into_iter()
.chunks_exact()
.collect::<Vec<[&str; 3]>>();
assert_eq!(actual, vec![["a", "b", "c"]]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment