orx-parallel 3.4.0

High performance, configurable and expressive parallel computation library.
Documentation
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use orx_parallel::*;
use rand::prelude::*;
use rand_chacha::ChaCha8Rng;
use rayon::iter::IntoParallelIterator;
use std::hint::black_box;

const SEED: u64 = 5426;
const FIB_UPPER_BOUND: u32 = 29;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Out1 {
    name: String,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Out2 {
    name: String,
    number: u32,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Out3 {
    out2: Out2,
    fib: u32,
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Out4 {
    a: String,
    b: char,
    fib: u32,
}

fn map1(idx: &usize) -> Out1 {
    let idx = *idx;
    let prefix = match idx % 7 {
        0 => "zero-",
        3 => "three-",
        _ => "sth-",
    };
    let fib = fibonacci(&(idx as u32 % FIB_UPPER_BOUND));
    let name = format!("{}-fib-{}", prefix, fib);
    Out1 { name }
}

fn filter1(output: &Out1) -> bool {
    let last_char = output.name.chars().last().unwrap();
    let last_digit: u32 = last_char.to_string().parse().unwrap();
    last_digit < 4
}

fn map2(input: Out1) -> Out2 {
    let number = (FIB_UPPER_BOUND + input.name.len() as u32).saturating_sub(10);
    let number = fibonacci(&(number & FIB_UPPER_BOUND));
    Out2 {
        name: number.to_string(),
        number,
    }
}

fn filter2(output: &Out2) -> bool {
    output.number % 2 == 0 || output.name.contains('0')
}

fn map3(input: Out2) -> Out3 {
    let fib = fibonacci(&input.number);
    Out3 { out2: input, fib }
}

fn map4(input: Out3) -> Out4 {
    let a = format!("{}!", input.out2.name);
    let b = input.out2.name.chars().next().unwrap();
    let fib = fibonacci(&((input.out2.number * 7) % FIB_UPPER_BOUND));
    Out4 { a, b, fib }
}

fn filter4(output: &Out4) -> bool {
    output.a.len() == 5 || output.b == 'x' || output.fib % 2 == 1
}

fn reduce(x: Out4, y: Out4) -> Out4 {
    let a = match x.fib % 2 == 0 {
        true => x.a,
        false => y.a,
    };
    let b = match y.fib % 2 == 0 {
        true => x.b,
        false => y.b,
    };
    let fib = x.fib + y.fib;
    Out4 { a, b, fib }
}

fn fibonacci(n: &u32) -> u32 {
    let mut a = 0;
    let mut b = 1;
    for _ in 0..*n {
        let c = a + b;
        a = b;
        b = c;
    }
    a
}

fn inputs(len: usize) -> Vec<usize> {
    let mut rng = ChaCha8Rng::seed_from_u64(SEED);
    (0..len)
        .map(|_| rng.random_range(0..FIB_UPPER_BOUND) as usize)
        .collect()
}

fn seq(inputs: &[usize]) -> Option<Out4> {
    inputs
        .iter()
        .map(map1)
        .filter(filter1)
        .map(map2)
        .filter(filter2)
        .map(map3)
        .map(map4)
        .filter(filter4)
        .reduce(reduce)
}

fn rayon(inputs: &[usize]) -> Option<Out4> {
    use rayon::iter::ParallelIterator;
    inputs
        .into_par_iter()
        .map(map1)
        .filter(filter1)
        .map(map2)
        .filter(filter2)
        .map(map3)
        .map(map4)
        .filter(filter4)
        .reduce_with(reduce)
}

fn orx(inputs: &[usize]) -> Option<Out4> {
    inputs
        .into_par()
        .map(map1)
        .filter(filter1)
        .map(map2)
        .filter(filter2)
        .map(map3)
        .map(map4)
        .filter(filter4)
        .reduce(reduce)
}

fn run(c: &mut Criterion) {
    let treatments = [65_536 * 2];

    let mut group = c.benchmark_group("collect_long_chain");

    for n in &treatments {
        let input = inputs(*n);
        let expected = seq(&input);

        group.bench_with_input(BenchmarkId::new("seq", n), n, |b, _| {
            assert_eq!(&expected, &seq(&input));
            b.iter(|| seq(black_box(&input)))
        });

        group.bench_with_input(BenchmarkId::new("rayon", n), n, |b, _| {
            assert_eq!(&expected, &rayon(&input));
            b.iter(|| rayon(black_box(&input)))
        });

        group.bench_with_input(BenchmarkId::new("orx", n), n, |b, _| {
            assert_eq!(&expected, &orx(&input));
            b.iter(|| orx(black_box(&input)))
        });
    }

    group.finish();
}

criterion_group!(benches, run);
criterion_main!(benches);