pub fn format_bytes(bytes: u64) -> String {
const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"];
if bytes < 1024 {
return format!("{bytes} B");
}
let mut value = bytes as f64;
let mut unit = 0usize;
while value >= 1024.0 && unit + 1 < UNITS.len() {
value /= 1024.0;
unit += 1;
}
format!("{value:.2} {}", UNITS[unit])
}
pub fn format_bytes_rate(bytes_per_sec: f64) -> String {
if !bytes_per_sec.is_finite() || bytes_per_sec <= 0.0 {
return "0 B/s".to_string();
}
format!("{}/s", format_bytes(bytes_per_sec.round() as u64))
}
pub fn format_count(n: u64) -> String {
match n {
0..=999 => n.to_string(),
1_000..=999_999 => format!("{:.1}k", n as f64 / 1_000.0),
1_000_000..=999_999_999 => format!("{:.1}M", n as f64 / 1_000_000.0),
_ => format!("{:.1}B", n as f64 / 1_000_000_000.0),
}
}
pub fn format_rate(per_sec: f64, unit: &str) -> String {
let value = if per_sec.is_finite() {
per_sec.max(0.0)
} else {
0.0
};
let formatted = if value >= 1_000_000_000.0 {
format!("{:.2}B", value / 1_000_000_000.0)
} else if value >= 1_000_000.0 {
format!("{:.2}M", value / 1_000_000.0)
} else if value >= 1_000.0 {
format!("{:.2}k", value / 1_000.0)
} else {
format!("{value:.2}")
};
format!("{formatted} {unit}/s")
}
pub fn format_percent(fraction: f64, decimals: usize) -> String {
let clamped = if fraction.is_finite() {
fraction.clamp(0.0, 1.0)
} else {
0.0
};
format!("{:.*}%", decimals, clamped * 100.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_bytes_zero() {
assert_eq!(format_bytes(0), "0 B");
}
#[test]
fn test_format_bytes_999() {
assert_eq!(format_bytes(999), "999 B");
}
#[test]
fn test_format_bytes_kb() {
assert_eq!(format_bytes(1024), "1.00 KB");
}
#[test]
fn test_format_bytes_mb() {
assert_eq!(format_bytes(1_048_576), "1.00 MB");
}
#[test]
fn test_format_bytes_gb() {
assert_eq!(format_bytes(1_073_741_824), "1.00 GB");
}
#[test]
fn test_format_bytes_tb() {
assert_eq!(format_bytes(1_099_511_627_776), "1.00 TB");
}
#[test]
fn test_format_count_hundreds() {
assert_eq!(format_count(999), "999");
}
#[test]
fn test_format_count_thousands() {
assert_eq!(format_count(1200), "1.2k");
}
#[test]
fn test_format_count_millions() {
assert_eq!(format_count(1_500_000), "1.5M");
}
#[test]
fn test_format_rate_basic() {
assert_eq!(format_rate(1500.0, "items"), "1.50k items/s");
}
#[test]
fn test_format_percent_zero() {
assert_eq!(format_percent(0.0, 0), "0%");
}
#[test]
fn test_format_percent_half() {
assert_eq!(format_percent(0.5, 0), "50%");
}
#[test]
fn test_format_percent_full() {
assert_eq!(format_percent(1.0, 0), "100%");
}
#[test]
fn test_format_percent_decimals() {
assert_eq!(format_percent(0.1234, 2), "12.34%");
}
#[test]
fn test_format_bytes_rate() {
assert_eq!(format_bytes_rate(1024.0), "1.00 KB/s");
}
}