moirai-iter 0.6.1

Parallel and async iterator combinators for Moirai concurrency library
Documentation
use crate::parallel::{IntoParallelIterator, ParallelIterator};

#[derive(Debug, PartialEq, Eq)]
struct WholeStreamCount(usize);

impl std::iter::Sum<u8> for WholeStreamCount {
    fn sum<I>(iter: I) -> Self
    where
        I: Iterator<Item = u8>,
    {
        Self(iter.count())
    }
}

impl std::iter::Product<u8> for WholeStreamCount {
    fn product<I>(iter: I) -> Self
    where
        I: Iterator<Item = u8>,
    {
        Self(iter.count() + 1)
    }
}

fn standard_sum_without_output_reassociation<I>(iter: I) -> WholeStreamCount
where
    I: ParallelIterator<Item = u8>,
{
    iter.sum()
}

fn standard_product_without_output_reassociation<I>(iter: I) -> WholeStreamCount
where
    I: ParallelIterator<Item = u8>,
{
    iter.product()
}

#[test]
fn standard_terminals_do_not_require_output_reassociation() {
    let data = vec![1_u8, 2, 3, 4];

    assert_eq!(
        standard_sum_without_output_reassociation(data.clone().into_par_iter()),
        WholeStreamCount(4)
    );
    assert_eq!(
        standard_product_without_output_reassociation(data.into_par_iter()),
        WholeStreamCount(5)
    );
}

#[derive(Debug, PartialEq, Eq)]
struct BatchSensitiveSum(usize);

impl std::iter::Sum<u8> for BatchSensitiveSum {
    fn sum<I>(iter: I) -> Self
    where
        I: Iterator<Item = u8>,
    {
        let count = iter.count();
        Self(count * count)
    }
}

impl std::iter::Sum<Self> for BatchSensitiveSum {
    fn sum<I>(iter: I) -> Self
    where
        I: Iterator<Item = Self>,
    {
        Self(iter.map(|partial| partial.0).sum())
    }
}

#[derive(Debug, PartialEq, Eq)]
struct BatchSensitiveProduct(usize);

impl std::iter::Product<u8> for BatchSensitiveProduct {
    fn product<I>(iter: I) -> Self
    where
        I: Iterator<Item = u8>,
    {
        Self(iter.count() + 1)
    }
}

impl std::iter::Product<Self> for BatchSensitiveProduct {
    fn product<I>(iter: I) -> Self
    where
        I: Iterator<Item = Self>,
    {
        Self(iter.fold(1, |accumulator, partial| {
            accumulator.wrapping_mul(partial.0)
        }))
    }
}

#[test]
fn batch_sensitive_traits_distinguish_standard_and_reassociated_terminals() {
    const LEN: usize = 8_192;
    let data = vec![1_u8; LEN];

    assert_eq!(
        data.clone().into_par_iter().sum::<BatchSensitiveSum>(),
        BatchSensitiveSum(LEN * LEN)
    );
    assert_eq!(
        data.clone()
            .into_par_iter()
            .sum_reassociated::<BatchSensitiveSum>(),
        BatchSensitiveSum(LEN)
    );
    assert_eq!(
        data.clone()
            .into_par_iter()
            .product::<BatchSensitiveProduct>(),
        BatchSensitiveProduct(LEN + 1)
    );
    assert_eq!(
        data.into_par_iter()
            .product_reassociated::<BatchSensitiveProduct>(),
        BatchSensitiveProduct(0)
    );
}

#[test]
fn reassociated_arithmetic_preserves_primitive_identities_and_values() {
    let data = vec![1_u64, 2, 3, 4, 5];
    assert_eq!(data.clone().into_par_iter().sum_reassociated::<u64>(), 15);
    assert_eq!(data.into_par_iter().product_reassociated::<u64>(), 120);
    assert_eq!(
        Vec::<u64>::new().into_par_iter().sum_reassociated::<u64>(),
        0
    );
    assert_eq!(
        Vec::<u64>::new()
            .into_par_iter()
            .product_reassociated::<u64>(),
        1
    );
}