#[allow(non_upper_case_globals)]
pub const unit_list: [(&str, usize); 6] = [
("", 0),
("k", 0),
("M", 1),
("G", 2),
("T", 2),
("P", 2),
];
pub fn humanize_bytes(num: f64, suffix: &str, si_prefix: bool) -> String {
if num == 0.0 {
return format!("0 {}", suffix); }
let div: f64 = if si_prefix { 1000.0 } else { 1024.0 }; let exponent: usize = {
let raw = if num != 0.0 { num.log(div) as i64 } else { 0 };
let max = (unit_list.len() as i64) - 1;
raw.min(max).max(0) as usize
};
let quotient: f64 = num / div.powi(exponent as i32); let (unit, decimals) = unit_list[exponent]; let mut unit: String = unit.to_string(); if !unit.is_empty() && !si_prefix {
unit = format!("{}i", unit.to_uppercase()); }
format!("{:.*} {}{}", decimals, quotient, unit, suffix)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_list_matches_upstream_shape() {
assert_eq!(unit_list.len(), 6);
assert_eq!(unit_list[0], ("", 0));
assert_eq!(unit_list[1], ("k", 0));
assert_eq!(unit_list[2], ("M", 1));
assert_eq!(unit_list[3], ("G", 2));
assert_eq!(unit_list[4], ("T", 2));
assert_eq!(unit_list[5], ("P", 2));
}
#[test]
fn zero_returns_suffix_only() {
assert_eq!(humanize_bytes(0.0, "B", false), "0 B");
assert_eq!(humanize_bytes(0.0, "iB", true), "0 iB");
}
#[test]
fn binary_prefix_matches_upstream() {
assert_eq!(humanize_bytes(1024.0, "B", false), "1 KiB");
assert_eq!(humanize_bytes(1024.0 * 1024.0, "B", false), "1.0 MiB");
assert_eq!(humanize_bytes(1024.0_f64.powi(3), "B", false), "1.00 GiB");
}
#[test]
fn si_prefix_matches_upstream() {
assert_eq!(humanize_bytes(1000.0, "B", true), "1 kB");
assert_eq!(humanize_bytes(1_000_000.0, "B", true), "1.0 MB");
}
}