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 ratatui::prelude::text;
use ratatui::style::Style;
use ratatui::text::Span;

use super::theme::{ACCENT_PROGRESS_RGB, PANEL_TEXT_RGB, rgb, style_color};

pub(super) fn progress_bar_line(
    elapsed_ms: u128,
    target_ms: u128,
    width: u16,
    no_color: bool,
    label: &str,
) -> text::Line<'static> {
    let bar_width = usize::from(width.saturating_sub(3)).max(1);
    let total_eighths = u128::try_from(bar_width)
        .unwrap_or(u128::MAX)
        .saturating_mul(8);
    let clamped_elapsed = if target_ms > 0 {
        elapsed_ms.min(target_ms)
    } else {
        0
    };
    let filled_eighths = if target_ms > 0 {
        clamped_elapsed
            .saturating_mul(total_eighths)
            .checked_div(target_ms)
            .unwrap_or(0)
    } else {
        0
    };
    let full_blocks = usize::try_from(filled_eighths.checked_div(8).unwrap_or(0)).unwrap_or(0);
    let rem = usize::try_from(filled_eighths.checked_rem(8).unwrap_or(0)).unwrap_or(0);
    let partial = ["", "", "", "", "", "", "", ""];
    let full_count = full_blocks.min(bar_width);
    let partial_block = partial.get(rem).copied().unwrap_or("");
    let partial_count = usize::from(rem > 0 && full_count < bar_width);
    let mut label_chars: Vec<char> = label.chars().collect();
    if label_chars.len() > bar_width {
        label_chars.truncate(bar_width);
    }
    let label_start = bar_width.saturating_sub(label_chars.len()) / 2;
    let mut label_cells: Vec<Option<char>> = vec![None; bar_width];
    for (offset, ch) in label_chars.into_iter().enumerate() {
        if let Some(pos) = label_start
            .checked_add(offset)
            .filter(|value| *value < bar_width)
            && let Some(cell) = label_cells.get_mut(pos)
        {
            *cell = Some(ch);
        }
    }
    let partial_char = partial_block.chars().next().unwrap_or(' ');

    let mut spans = Vec::with_capacity(bar_width.saturating_add(2));
    spans.push(Span::raw("["));
    for idx in 0..bar_width {
        let is_partial_cell = partial_count == 1 && idx == full_count;
        let is_filled_cell = idx < full_count || is_partial_cell;
        if let Some(ch) = label_cells.get(idx).copied().flatten() {
            spans.push(Span::styled(
                ch.to_string(),
                label_cell_style(no_color, is_filled_cell),
            ));
            continue;
        }
        if idx < full_count {
            spans.push(Span::styled(
                "",
                style_color(no_color, rgb(ACCENT_PROGRESS_RGB)),
            ));
            continue;
        }
        if partial_count == 1 && idx == full_count {
            spans.push(Span::styled(
                partial_char.to_string(),
                style_color(no_color, rgb(ACCENT_PROGRESS_RGB)),
            ));
            continue;
        }
        spans.push(Span::raw(" "));
    }
    spans.push(Span::raw("]"));
    text::Line::from(spans)
}

fn label_cell_style(no_color: bool, on_filled_cell: bool) -> Style {
    if no_color {
        return Style::default();
    }
    let style = Style::default().fg(rgb(PANEL_TEXT_RGB));
    if on_filled_cell {
        style.bg(rgb(ACCENT_PROGRESS_RGB))
    } else {
        style
    }
}

#[cfg(test)]
mod tests {
    use super::{ACCENT_PROGRESS_RGB, progress_bar_line, rgb};

    #[test]
    fn label_on_filled_cell_keeps_progress_background() {
        let line = progress_bar_line(9, 10, 20, false, "x");
        let bg = line
            .spans
            .iter()
            .find(|span| span.content.as_ref() == "x")
            .and_then(|span| span.style.bg);
        assert_eq!(bg, Some(rgb(ACCENT_PROGRESS_RGB)));
    }

    #[test]
    fn label_on_empty_cell_has_no_background_fill() {
        let line = progress_bar_line(1, 10, 20, false, "x");
        let bg = line
            .spans
            .iter()
            .find(|span| span.content.as_ref() == "x")
            .and_then(|span| span.style.bg);
        assert_eq!(bg, None);
    }
}