Skip to main content

spider_util/
formatters.rs

1//! Formatting utilities for the spider framework.
2//!
3//! This module provides traits and implementations for formatting
4//! durations, byte sizes, and rates in a consistent manner.
5
6use std::time::Duration;
7
8/// Trait for formatting duration values.
9pub trait DurationFormatter {
10    /// Formats a duration in a human-readable format.
11    fn formatted_duration(&self, duration: Duration) -> String;
12
13    /// Formats a request time, showing milliseconds or seconds as appropriate.
14    fn formatted_request_time(&self, duration: Option<Duration>) -> String;
15}
16
17/// Default implementation for duration formatting.
18pub struct DefaultDurationFormatter;
19
20impl DurationFormatter for DefaultDurationFormatter {
21    fn formatted_duration(&self, duration: Duration) -> String {
22        format!("{:?}", duration)
23    }
24
25    fn formatted_request_time(&self, duration: Option<Duration>) -> String {
26        match duration {
27            Some(d) => {
28                if d.as_millis() < 1000 {
29                    format!("{} ms", d.as_millis())
30                } else {
31                    format!("{:.2} s", d.as_secs_f64())
32                }
33            }
34            None => "N/A".to_string(),
35        }
36    }
37}
38
39/// Trait for formatting byte values.
40pub trait ByteFormatter {
41    /// Formats a byte count in a human-readable format (B, KB, MB, GB).
42    fn formatted_bytes(&self, bytes: usize) -> String;
43}
44
45/// Default implementation for byte formatting.
46pub struct DefaultByteFormatter;
47
48impl ByteFormatter for DefaultByteFormatter {
49    fn formatted_bytes(&self, bytes: usize) -> String {
50        const KB: usize = 1024;
51        const MB: usize = 1024 * KB;
52        const GB: usize = 1024 * MB;
53
54        if bytes >= GB {
55            format!("{:.2} GB", bytes as f64 / GB as f64)
56        } else if bytes >= MB {
57            format!("{:.2} MB", bytes as f64 / MB as f64)
58        } else if bytes >= KB {
59            format!("{:.2} KB", bytes as f64 / KB as f64)
60        } else {
61            format!("{} B", bytes)
62        }
63    }
64}
65
66/// Trait for calculating rates.
67pub trait RateCalculator {
68    /// Calculates a rate given a count and elapsed time.
69    fn calculate_rate(&self, count: usize, elapsed: Duration) -> f64;
70}
71
72/// Default implementation for rate calculation.
73pub struct DefaultRateCalculator;
74
75impl RateCalculator for DefaultRateCalculator {
76    fn calculate_rate(&self, count: usize, elapsed: Duration) -> f64 {
77        let elapsed = elapsed.as_secs_f64();
78        if elapsed > 0.0 {
79            count as f64 / elapsed
80        } else {
81            0.0
82        }
83    }
84}
85
86// ============================================================================
87// Convenience Functions
88// ============================================================================
89
90/// Formats a duration in a human-readable format.
91pub fn format_duration(duration: Duration) -> String {
92    DefaultDurationFormatter.formatted_duration(duration)
93}
94
95/// Formats a request time, showing milliseconds or seconds as appropriate.
96pub fn format_request_time(duration: Option<Duration>) -> String {
97    DefaultDurationFormatter.formatted_request_time(duration)
98}
99
100/// Formats a byte count in a human-readable format.
101pub fn format_bytes(bytes: usize) -> String {
102    DefaultByteFormatter.formatted_bytes(bytes)
103}
104
105/// Calculates a rate given a count and elapsed time.
106pub fn calculate_rate(count: usize, elapsed: Duration) -> f64 {
107    DefaultRateCalculator.calculate_rate(count, elapsed)
108}