const EIB: u64 = 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
const PIB: u64 = 1024 * 1024 * 1024 * 1024 * 1024;
const TIB: u64 = 1024 * 1024 * 1024 * 1024;
const GIB: u64 = 1024 * 1024 * 1024;
const MIB: u64 = 1024 * 1024;
const KIB: u64 = 1024;
const EIBM1: u64 = EIB - 1;
const PIBM1: u64 = PIB - 1;
const TIBM1: u64 = TIB - 1;
const GIBM1: u64 = GIB - 1;
const MIBM1: u64 = MIB - 1;
const EB: u64 = 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
const PB: u64 = 1000 * 1000 * 1000 * 1000 * 1000;
const TB: u64 = 1000 * 1000 * 1000 * 1000;
const GB: u64 = 1000 * 1000 * 1000;
const MB: u64 = 1000 * 1000;
const KB: u64 = 1000;
const EBM1: u64 = EB - 1;
const PBM1: u64 = PB - 1;
const TBM1: u64 = TB - 1;
const GBM1: u64 = GB - 1;
const MBM1: u64 = MB - 1;
pub fn prettybytes(count: u64, binary: bool, decimal: bool) -> String {
let mut ret = String::new();
if binary || decimal {
if count < KIB {
ret.push_str(&format!("{} bytes", count))
} else {
let bin = match count {
EIB..=u64::MAX => format!("{:.4} EiB", ((count / TIB) as f64) / (MIB as f64)),
PIB..=EIBM1 => format!("{:.4} PiB", ((count / GIB) as f64) / (MIB as f64)),
TIB..=PIBM1 => format!("{:.4} TiB", ((count / MIB) as f64) / (MIB as f64)),
GIB..=TIBM1 => format!("{:.2} GiB", ((count / MIB) as f64) / (KIB as f64)),
MIB..=GIBM1 => format!("{:.1} MiB", (count as f64) / (MIB as f64)),
0..=MIBM1 => format!("{:.1} kiB", (count as f64) / (KIB as f64)),
};
let dec = match count {
EB..=u64::MAX => format!("{:.4} EB", ((count / TB) as f64) / (MB as f64)),
PB..=EBM1 => format!("{:.4} PB", ((count / GB) as f64) / (MB as f64)),
TB..=PBM1 => format!("{:.4} TB", ((count / MB) as f64) / (MB as f64)),
GB..=TBM1 => format!("{:.2} GB", ((count / MB) as f64) / (KB as f64)),
MB..=GBM1 => format!("{:.1} MB", (count as f64) / (MB as f64)),
0..=MBM1 => format!("{:.1} kB", (count as f64) / (KB as f64)),
};
if binary {
ret.push_str(&bin);
}
if decimal {
let len = ret.len();
if len > 0 { ret.push_str(" ("); }
ret.push_str(&dec);
if len > 0 { ret.push_str(")"); }
}
}
}
ret
}
pub fn parsebytes(s: &str) -> Result<u64, <u64 as std::str::FromStr>::Err> {
let s = s.trim().to_lowercase();
if let Some(s) = s.strip_suffix("eib") {
Ok(s.trim().parse::<u64>()? * EIB)
} else if let Some(s) = s.strip_suffix("pib") {
Ok(s.trim().parse::<u64>()? * PIB)
} else if let Some(s) = s.strip_suffix("tib") {
Ok(s.trim().parse::<u64>()? * TIB)
} else if let Some(s) = s.strip_suffix("gib") {
Ok(s.trim().parse::<u64>()? * GIB)
} else if let Some(s) = s.strip_suffix("mib") {
Ok(s.trim().parse::<u64>()? * MIB)
} else if let Some(s) = s.strip_suffix("kib") {
Ok(s.trim().parse::<u64>()? * KIB)
} else if let Some(s) = s.strip_suffix("e") {
Ok(s.trim().parse::<u64>()? * EIB)
} else if let Some(s) = s.strip_suffix("p") {
Ok(s.trim().parse::<u64>()? * PIB)
} else if let Some(s) = s.strip_suffix("t") {
Ok(s.trim().parse::<u64>()? * TIB)
} else if let Some(s) = s.strip_suffix("g") {
Ok(s.trim().parse::<u64>()? * GIB)
} else if let Some(s) = s.strip_suffix("m") {
Ok(s.trim().parse::<u64>()? * MIB)
} else if let Some(s) = s.strip_suffix("k") {
Ok(s.trim().parse::<u64>()? * KIB)
} else if let Some(s) = s.strip_suffix("eb") {
Ok(s.trim().parse::<u64>()? * EB)
} else if let Some(s) = s.strip_suffix("pb") {
Ok(s.trim().parse::<u64>()? * PB)
} else if let Some(s) = s.strip_suffix("tb") {
Ok(s.trim().parse::<u64>()? * TB)
} else if let Some(s) = s.strip_suffix("gb") {
Ok(s.trim().parse::<u64>()? * GB)
} else if let Some(s) = s.strip_suffix("mb") {
Ok(s.trim().parse::<u64>()? * MB)
} else if let Some(s) = s.strip_suffix("kb") {
Ok(s.trim().parse::<u64>()? * KB)
} else {
s.parse()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_prettybytes() {
assert_eq!(prettybytes(42, true, true),
"42 bytes");
assert_eq!(prettybytes(42 * 1024, true, true),
"42.0 kiB (43.0 kB)");
assert_eq!(prettybytes(42 * 1024 * 1024, true, true),
"42.0 MiB (44.0 MB)");
assert_eq!(prettybytes(42 * 1024 * 1024 * 1024, true, true),
"42.00 GiB (45.10 GB)");
assert_eq!(prettybytes(42 * 1024 * 1024 * 1024 * 1024, true, true),
"42.0000 TiB (46.1795 TB)");
assert_eq!(prettybytes(42 * 1024 * 1024 * 1024 * 1024 * 1024, true, true),
"42.0000 PiB (47.2878 PB)");
assert_eq!(prettybytes(2 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, true, true),
"2.0000 EiB (2.3058 EB)");
assert_eq!(prettybytes(42, true, false),
"42 bytes");
assert_eq!(prettybytes(42, false, true),
"42 bytes");
assert_eq!(prettybytes(42, false, false),
"");
assert_eq!(prettybytes(42 * 1024, true, false),
"42.0 kiB");
assert_eq!(prettybytes(42 * 1024, false, true),
"43.0 kB");
assert_eq!(prettybytes(42 * 1024, false, false),
"");
}
#[test]
fn test_parsebytes() {
assert_eq!(parsebytes("42").unwrap(),
42);
assert_eq!(parsebytes("42kib").unwrap(),
42 * 1024);
assert_eq!(parsebytes("42 mib").unwrap(),
42 * 1024 * 1024);
assert_eq!(parsebytes(" 42 gib ").unwrap(),
42 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("42Tib").unwrap(),
42 * 1024 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("42PiB").unwrap(),
42 * 1024 * 1024 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("2 EIB ").unwrap(),
2 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("42k").unwrap(),
42 * 1024);
assert_eq!(parsebytes("42 m").unwrap(),
42 * 1024 * 1024);
assert_eq!(parsebytes(" 42 g ").unwrap(),
42 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("42T").unwrap(),
42 * 1024 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("42P").unwrap(),
42 * 1024 * 1024 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("2 E ").unwrap(),
2 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024);
assert_eq!(parsebytes("42kb").unwrap(),
42 * 1000);
assert_eq!(parsebytes("42 mb").unwrap(),
42 * 1000 * 1000);
assert_eq!(parsebytes(" 42 gb ").unwrap(),
42 * 1000 * 1000 * 1000);
assert_eq!(parsebytes("42Tb").unwrap(),
42 * 1000 * 1000 * 1000 * 1000);
assert_eq!(parsebytes("42PB").unwrap(),
42 * 1000 * 1000 * 1000 * 1000 * 1000);
assert_eq!(parsebytes("2 EB ").unwrap(),
2 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000);
}
}