#![allow(clippy::disallowed_methods, clippy::print_stdout)]

use criterion::Criterion;
use rand::distr::Alphanumeric;
use rand::distr::SampleString;
use smol_str::ToSmolStr;
use smol_str::format_smolstr;

use alloc_profiler::AllocProfile;
use alloc_profiler::global::GlobalAllocProfiler;

#[global_allocator]
static ALLOC: GlobalAllocProfiler<std::alloc::System> =
    GlobalAllocProfiler::new(std::alloc::System);

/// 12: small (inline)
/// 50: medium (heap)
/// 1000: large (heap)
const TEST_LENS: [usize; 5] = [12, 22, 23, 50, 1000];

// See: https://github.com/rust-analyzer/smol_str/blob/549e76bc53b4deffe7c9f770a92be294e057b0c7/benches/bench.rs#L11
fn format_smolstr_bench(c: &mut Criterion) {
    for len in TEST_LENS {
        let n = rand::random_range(10000..99999);
        let str_len = len.checked_sub(n.to_smolstr().len()).unwrap();
        let str = Alphanumeric.sample_string(&mut rand::rng(), str_len);

        let mut iter_profile = AllocProfile::default();
        c.bench_function(&format!("format_smolstr! len={len}"), |b| {
            let mut v = <_>::default();
            b.iter(|| {
                let _guard = ALLOC.profile_guard(&mut iter_profile);
                v = format_smolstr!("{str}-{n}");
            });
            assert_eq!(v, format!("{str}-{n}"));
        });
        println!(
            "XXX per iteration profile:{:?}",
            iter_profile.per_iteration()
        );
    }
}

fn format_string_bench(c: &mut Criterion) {
    for len in TEST_LENS {
        let n = rand::random_range(10000..99999);
        let str_len = len.checked_sub(n.to_string().len()).unwrap();
        let str = Alphanumeric.sample_string(&mut rand::rng(), str_len);

        let mut iter_profile = AllocProfile::default();
        c.bench_function(&format!("format! len={len}"), |b| {
            let mut v = <_>::default();
            b.iter(|| {
                let _guard = ALLOC.profile_guard(&mut iter_profile);
                v = format!("{str}-{n}");
            });
            assert_eq!(v, format!("{str}-{n}"));
        });
        println!(
            "XXX per iteration profile:{:?}",
            iter_profile.per_iteration()
        );
    }
}

criterion::criterion_group! {
    name = benches;
    config = criterion::Criterion::default()
        .sample_size(10)
        .warm_up_time(std::time::Duration::from_secs(1))
        .measurement_time(std::time::Duration::from_secs(1))
        .sample_size(10);
    targets = format_smolstr_bench, format_string_bench
}

criterion::criterion_main!(benches);
