strest 0.1.10

Blazing-fast async HTTP load tester in Rust - lock-free design, real-time stats, distributed runs, and optional chart exports for high-load API testing.
Documentation
use std::collections::BTreeMap;

use crate::metrics::AggregatedMetricSample;

fn sorted_samples(samples: &[AggregatedMetricSample]) -> Vec<AggregatedMetricSample> {
    let mut out = samples.to_vec();
    out.sort_by_key(|sample| sample.elapsed_ms);
    out
}

fn bucket_last_value(
    samples: &[AggregatedMetricSample],
    bucket_ms: u64,
    value: fn(&AggregatedMetricSample) -> u64,
) -> Vec<(u64, u64)> {
    let mut buckets: BTreeMap<u64, u64> = BTreeMap::new();
    let bucket_ms = bucket_ms.max(1);
    for sample in samples {
        let bucket = sample.elapsed_ms.checked_div(bucket_ms).unwrap_or(0);
        buckets.insert(bucket, value(sample));
    }
    buckets.into_iter().collect()
}

pub(super) fn bucket_last_value_u64(
    samples: &[AggregatedMetricSample],
    bucket_ms: u64,
    value: fn(&AggregatedMetricSample) -> u64,
) -> Vec<(u64, u64)> {
    bucket_last_value(samples, bucket_ms, value)
}

pub(super) fn compute_rps_series(samples: &[AggregatedMetricSample]) -> Vec<(u64, u64)> {
    let sorted = sorted_samples(samples);
    let mut buckets: BTreeMap<u64, u64> = BTreeMap::new();
    for window in sorted.windows(2) {
        let Some(prev) = window.first() else { continue };
        let Some(curr) = window.get(1) else { continue };
        if curr.elapsed_ms <= prev.elapsed_ms {
            continue;
        }
        let delta = curr.total_requests.saturating_sub(prev.total_requests);
        let delta_ms = curr.elapsed_ms.saturating_sub(prev.elapsed_ms).max(1);
        let rps = u64::try_from(
            u128::from(delta)
                .saturating_mul(1000)
                .checked_div(u128::from(delta_ms))
                .unwrap_or(0),
        )
        .unwrap_or(u64::MAX);
        let sec_bucket = curr.elapsed_ms.checked_div(1000).unwrap_or(0);
        buckets.insert(sec_bucket, rps);
    }
    buckets.into_iter().collect()
}