pub trait IteratorForEachCount: Iterator {
fn for_each_count<F>(self, f: F) -> usize
where
Self: Sized,
F: FnMut(Self::Item),
{
#[inline]
fn call<T>(mut f: impl FnMut(T)) -> impl FnMut(usize, T) -> usize {
move |count, item| {
f(item);
count + 1
}
}
self.fold(0_usize, call(f))
}
fn try_for_each_count<F, E>(&mut self, f: F) -> Result<usize, E>
where
Self: Sized,
F: FnMut(Self::Item) -> Result<(), E>,
{
#[inline]
fn call<T, E>(
mut f: impl FnMut(T) -> Result<(), E>,
) -> impl FnMut(usize, T) -> Result<usize, E> {
move |count, item| {
f(item)?;
Ok(count + 1)
}
}
self.try_fold(0_usize, call(f))
}
}
impl<T> IteratorForEachCount for T where T: Iterator {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_iterator() {
let count = std::iter::empty::<i32>().for_each_count(|_| {});
assert_eq!(count, 0);
}
#[test]
fn test_for_each_count_with_side_effects() {
let mut sum = 0;
let count = (1..=5).for_each_count(|x| sum += x);
assert_eq!(count, 5);
assert_eq!(sum, 15);
}
#[test]
fn test_for_each_count_without_side_effects() {
let count = (1..=3).for_each_count(|_| {});
assert_eq!(count, 3);
}
#[test]
fn test_for_each_count_with_vec() {
let mut vec = Vec::new();
let count = (1..=4).for_each_count(|x| vec.push(x));
assert_eq!(count, 4);
assert_eq!(vec, vec![1, 2, 3, 4]);
}
#[test]
fn test_for_each_count_with_filter() {
let mut sum = 0;
let count = (1..=10).filter(|x| x % 2 == 0).for_each_count(|x| sum += x);
assert_eq!(count, 5);
assert_eq!(sum, 30);
}
#[test]
fn test_try_for_each_count_success() {
let mut sum = 0;
let count = (1..=5).try_for_each_count(|x| -> Result<(), ()> {
sum += x;
Ok(())
});
assert_eq!(count.unwrap(), 5);
assert_eq!(sum, 15);
}
#[test]
fn test_try_for_each_count_error() {
let result = (1..=5).try_for_each_count(|x| -> Result<(), &str> {
if x == 3 { Err("error at 3") } else { Ok(()) }
});
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "error at 3");
}
#[test]
fn test_try_for_each_count_empty() {
let count = std::iter::empty::<i32>().try_for_each_count(|_| -> Result<(), ()> { Ok(()) });
assert_eq!(count.unwrap(), 0);
}
#[test]
fn test_try_for_each_count_with_filter() {
let mut sum = 0;
let count = (1..=10)
.filter(|x| x % 2 == 0)
.try_for_each_count(|x| -> Result<(), ()> {
sum += x;
Ok(())
});
assert_eq!(count.unwrap(), 5);
assert_eq!(sum, 30);
}
}