use criterion::{criterion_group, criterion_main, Criterion, Fun};
/**
 * This module benchmarks whether `Vec` allocations are optimized on return.
 */
use rand::distributions::{Distribution, Standard};
use rand::prelude::*;

static SEED: [u8; 32] = [3; 32];
static BUF_SIZE: usize = 100_000;

#[inline]
fn operation(v: &[f64]) -> f64 {
    v.first().unwrap() + v.last().unwrap()
}

#[inline]
fn random_vec_val(n: usize) -> Vec<f64>
where
    Standard: Distribution<f64>,
{
    let mut rng: StdRng = SeedableRng::from_seed(SEED);
    (0..n).map(|_| rng.gen()).collect()
}

#[inline]
fn random_vec_mut(vec: &mut Vec<f64>, n: usize)
where
    Standard: Distribution<f64>,
{
    let mut rng: StdRng = SeedableRng::from_seed(SEED);
    vec.clear();
    vec.extend((0..n).map(|_| rng.gen::<f64>()));
}

fn return_vec(c: &mut Criterion) {
    let by_val = Fun::new("Modify By Return", move |b, _| {
        let mut v = random_vec_val(BUF_SIZE);
        b.iter(|| {
            let a = operation(&v);
            v = random_vec_val(BUF_SIZE);
            a + operation(&v)
        })
    });

    let by_mut = Fun::new("Modfiy By Mut Borrow", move |b, _| {
        let mut v = random_vec_val(BUF_SIZE);
        b.iter(|| {
            let a = operation(&v);
            random_vec_mut(&mut v, BUF_SIZE);
            a + operation(&v)
        })
    });

    let fns = vec![by_val, by_mut];
    c.bench_functions("Return Vec", fns, ());
}

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