Update unit conversions (#597)

* Refactor Dir

* Update unit conversions
This commit is contained in:
Vincent Ollivier 2024-03-16 11:00:45 +01:00 committed by GitHub
parent 5ca0894241
commit 4d0c956a0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 43 additions and 35 deletions

View File

@ -9,39 +9,53 @@ pub enum SizeUnit {
}
impl SizeUnit {
pub fn format(&self, size: usize) -> String {
pub fn format(&self, bytes: usize) -> String {
match self {
SizeUnit::None => format!("{}", size),
SizeUnit::Binary => binary_size(size),
SizeUnit::Decimal => decimal_size(size),
SizeUnit::None => format!("{}", bytes),
SizeUnit::Binary => readable_size(bytes, 1024),
SizeUnit::Decimal => readable_size(bytes, 1000),
}
}
}
const PREFIXES: [&str; 5] = ["", "K", "M", "G", "T"];
fn binary_size(size: usize) -> String {
let n = PREFIXES.len();
for i in 0..n {
let prefix = PREFIXES[i];
if size < (1 << ((i + 1) * 10)) || i == n - 1 {
let s = ((size * 10) >> (i * 10)) as f64 / 10.0;
let s = if s >= 10.0 { libm::round(s) } else { s };
return format!("{}{}", s, prefix);
}
fn readable_size(bytes: usize, divisor: usize) -> String {
let units = ["", "K", "M", "G", "T"];
let d = divisor as f64;
let mut s = bytes as f64;
let mut i = 0;
while s >= d && i < units.len() - 1 {
s /= d;
i += 1;
}
unreachable!();
let p = if i > 0 && s < 10.0 { 1 } else { 0 };
format!("{:.2$}{}", s, units[i], p)
}
fn decimal_size(size: usize) -> String {
let n = PREFIXES.len();
for i in 0..n {
let prefix = PREFIXES[i];
if size < usize::pow(10, 3 * (i + 1) as u32) || i == n - 1 {
let s = (size as f64) / libm::pow(10.0, 3.0 * (i as f64));
let precision = if s >= 10.0 { 0 } else { 1 };
return format!("{:.2$}{}", s, prefix, precision);
}
}
unreachable!();
#[test_case]
fn test_binary_size() {
let unit = SizeUnit::Binary;
assert_eq!(unit.format(1), "1");
assert_eq!(unit.format(10), "10");
assert_eq!(unit.format(100), "100");
assert_eq!(unit.format(1000), "1000");
assert_eq!(unit.format(1024), "1.0K");
assert_eq!(unit.format(1120), "1.1K");
assert_eq!(unit.format(1160), "1.1K");
assert_eq!(unit.format(15000), "15K");
assert_eq!(unit.format(1000000), "977K");
}
#[test_case]
fn test_decimal_size() {
let unit = SizeUnit::Decimal;
assert_eq!(unit.format(1), "1");
assert_eq!(unit.format(10), "10");
assert_eq!(unit.format(100), "100");
assert_eq!(unit.format(1000), "1.0K");
assert_eq!(unit.format(1024), "1.0K");
assert_eq!(unit.format(1120), "1.1K");
assert_eq!(unit.format(1160), "1.2K");
assert_eq!(unit.format(1500), "1.5K");
assert_eq!(unit.format(15000), "15K");
assert_eq!(unit.format(1000000), "1.0M");
}

View File

@ -77,14 +77,8 @@ impl Dir {
for name in pathname.trim_start_matches('/').split('/') {
match dir.find(name) {
Some(dir_entry) => {
if dir_entry.is_dir() {
dir = dir_entry.into()
} else {
return None;
}
}
None => return None,
Some(entry) if entry.is_dir() => dir = entry.into(),
_ => return None,
}
}
Some(dir)