spider_util/
formatters.rs1use std::time::Duration;
4
5pub trait DurationFormatter {
7 fn formatted_duration(&self, duration: Duration) -> String;
9
10 fn formatted_request_time(&self, duration: Option<Duration>) -> String;
12}
13
14pub struct DefaultDurationFormatter;
16
17fn format_human_duration(duration: Duration) -> String {
18 let total_secs = duration.as_secs();
19 let hours = total_secs / 3600;
20 let minutes = (total_secs % 3600) / 60;
21 let seconds = duration.as_secs_f64() % 60.0;
22
23 if hours > 0 {
24 format!("{hours}h {minutes:02}m {seconds:05.2}s")
25 } else if minutes > 0 {
26 format!("{minutes}m {seconds:05.2}s")
27 } else if total_secs > 0 {
28 format!("{:.2}s", duration.as_secs_f64())
29 } else if duration.as_millis() > 0 {
30 format!("{}ms", duration.as_millis())
31 } else {
32 format!("{}us", duration.as_micros())
33 }
34}
35
36impl DurationFormatter for DefaultDurationFormatter {
37 fn formatted_duration(&self, duration: Duration) -> String {
38 format_human_duration(duration)
39 }
40
41 fn formatted_request_time(&self, duration: Option<Duration>) -> String {
42 match duration {
43 Some(d) => {
44 if d.as_millis() < 1000 {
45 format!("{} ms", d.as_millis())
46 } else {
47 format!("{:.2} s", d.as_secs_f64())
48 }
49 }
50 None => "N/A".to_string(),
51 }
52 }
53}
54
55pub trait ByteFormatter {
57 fn formatted_bytes(&self, bytes: usize) -> String;
59}
60
61pub struct DefaultByteFormatter;
63
64impl ByteFormatter for DefaultByteFormatter {
65 fn formatted_bytes(&self, bytes: usize) -> String {
66 const KB: usize = 1024;
67 const MB: usize = 1024 * KB;
68 const GB: usize = 1024 * MB;
69
70 if bytes >= GB {
71 format!("{:.2} GB", bytes as f64 / GB as f64)
72 } else if bytes >= MB {
73 format!("{:.2} MB", bytes as f64 / MB as f64)
74 } else if bytes >= KB {
75 format!("{:.2} KB", bytes as f64 / KB as f64)
76 } else {
77 format!("{} B", bytes)
78 }
79 }
80}
81
82pub trait RateCalculator {
84 fn calculate_rate(&self, count: usize, elapsed: Duration) -> f64;
86}
87
88pub struct DefaultRateCalculator;
90
91impl RateCalculator for DefaultRateCalculator {
92 fn calculate_rate(&self, count: usize, elapsed: Duration) -> f64 {
93 let elapsed = elapsed.as_secs_f64();
94 if elapsed > 0.0 {
95 count as f64 / elapsed
96 } else {
97 0.0
98 }
99 }
100}
101
102pub fn format_duration(duration: Duration) -> String {
108 DefaultDurationFormatter.formatted_duration(duration)
109}
110
111pub fn format_request_time(duration: Option<Duration>) -> String {
113 DefaultDurationFormatter.formatted_request_time(duration)
114}
115
116pub fn format_bytes(bytes: usize) -> String {
118 DefaultByteFormatter.formatted_bytes(bytes)
119}
120
121pub fn calculate_rate(count: usize, elapsed: Duration) -> f64 {
123 DefaultRateCalculator.calculate_rate(count, elapsed)
124}