diff --git a/Cargo.lock b/Cargo.lock index 9fef91a..b80142e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,7 +167,6 @@ version = "0.1.2" dependencies = [ "assert_cmd", "clap", - "humanize-bytes", "predicates", "spinoff", ] @@ -187,15 +186,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "humanize-bytes" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a92093c50b761e6ba595c797365301d3aaae67db1382ddf9d5d0092d98df799" -dependencies = [ - "smartstring", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -344,17 +334,6 @@ dependencies = [ "syn", ] -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - [[package]] name = "spinoff" version = "0.8.0" @@ -366,12 +345,6 @@ dependencies = [ "paste", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" @@ -407,12 +380,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "wait-timeout" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 9387d88..7c24aa7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ exclude = ["/.github/"] [dependencies] clap = { version = "4.5.16", features = ["derive"] } -humanize-bytes = "1.0.6" spinoff = { version = "0.8.0", features = ["dots"] } [dev-dependencies] diff --git a/src/bytes.rs b/src/bytes.rs new file mode 100644 index 0000000..082e95f --- /dev/null +++ b/src/bytes.rs @@ -0,0 +1,44 @@ +#![allow(clippy::cast_precision_loss)] + +const UNITS: [&str; 6] = ["B", "KB", "MB", "GB", "TB", "PB"]; + +const BASE: u64 = 1000; + +pub fn humanize(bytes: u64) -> String { + if bytes < BASE { + return format!("{bytes} B"); + } + let exponent = bytes.ilog10() / BASE.ilog10(); + let unit = UNITS[exponent as usize]; + let value = bytes as f64 / BASE.pow(exponent) as f64; + let precision = match unit { + "KB" => 0, + "MB" => 1, + _ => 2, + }; + format!("{value:.precision$} {unit}") +} + +#[cfg(test)] +mod test { + use super::humanize; + + #[test] + fn test_humanize() { + assert_eq!(humanize(0), "0 B"); + assert_eq!(humanize(256), "256 B"); + assert_eq!(humanize(512), "512 B"); + assert_eq!(humanize(1_000), "1 KB"); + assert_eq!(humanize(2_650), "3 KB"); + assert_eq!(humanize(737_525), "738 KB"); + assert_eq!(humanize(1_000_000), "1.0 MB"); + assert_eq!(humanize(1_240_000), "1.2 MB"); + assert_eq!(humanize(1_250_000), "1.2 MB"); + assert_eq!(humanize(1_260_000), "1.3 MB"); + assert_eq!(humanize(10_525_000), "10.5 MB"); + assert_eq!(humanize(2_886_000_000), "2.89 GB"); + assert_eq!(humanize(200_500_150_001), "200.50 GB"); + assert_eq!(humanize(50_000_000_000_000), "50.00 TB"); + assert_eq!(humanize(1_421_000_000_000_000), "1.42 PB"); + } +} diff --git a/src/files.rs b/src/files.rs index 9e91813..7be37a0 100644 --- a/src/files.rs +++ b/src/files.rs @@ -3,7 +3,7 @@ use std::fs::ReadDir; use std::io; use std::path::PathBuf; -use humanize_bytes::humanize_bytes_decimal; +use crate::bytes; pub fn from_path(path: &str) -> io::Result { let dir = std::fs::read_dir(path)?; @@ -27,7 +27,7 @@ impl File { impl Display for File { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}: {}", self.size, self.path.display()) + write!(f, "{} {}", self.size, self.path.display()) } } @@ -36,7 +36,7 @@ pub struct Size(u64); impl Display for Size { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:>8}", humanize_bytes_decimal!(self.0)) + write!(f, "{}", bytes::humanize(self.0)) } } @@ -84,11 +84,11 @@ mod test { let cases = vec![ Case { file: File::new("/path/to/file.txt", 1000), - want: " 1 kB: /path/to/file.txt", + want: "1 KB /path/to/file.txt", }, Case { file: File::new("/path/to/file.txt", 34250), - want: " 34.2 kB: /path/to/file.txt", + want: "34 KB /path/to/file.txt", }, ]; for case in cases { diff --git a/src/lib.rs b/src/lib.rs index 0264acd..73d2587 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +mod bytes; mod files; use std::{collections::BTreeMap, io}; diff --git a/tests/cli.rs b/tests/cli.rs index e0a187f..cd53d63 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -43,10 +43,10 @@ fn binary_with_no_args_prints_top_5_largest_files_under_working_directory() { fn binary_with_path_arg_prints_the_top_5_largest_files_under_the_given_path() { let want = [ "*** Top 5 largest files ***", - " 7 B: ./testdata/en/world.txt", - " 6 B: ./testdata/es/mundo.txt", - " 6 B: ./testdata/en/hello.txt", - " 5 B: ./testdata/es/hola.txt", + "7 B ./testdata/en/world.txt", + "6 B ./testdata/es/mundo.txt", + "6 B ./testdata/en/hello.txt", + "5 B ./testdata/es/hola.txt", ]; Command::cargo_bin("dstats") .unwrap()