diff --git a/Cargo.toml b/Cargo.toml index f8136f0..7dd52d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "humanize-bytes" -version = "1.0.5" +version = "1.0.6" edition = "2021" authors = ["Jacob T. "] homepage = "https://github.com/trueb2/humanize-bytes" diff --git a/src/lib.rs b/src/lib.rs index a4db546..609cd1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,38 +55,48 @@ mod binary { /// #[macro_export] macro_rules! humanize_bytes_binary { - ($value:expr) => { - { - use ::humanize_bytes::smartstring::{SmartString, LazyCompact}; - use ::core::fmt::Write; - let num_bytes = { $value } as f64; - if num_bytes <= 0.0 { - "0 B".into() - } else if num_bytes < 1024.0 { - let mut result = SmartString::::new(); - write!(result, "{} B", num_bytes as u16).unwrap(); - result - } else { - const SUFFIX: [&str; 11] = ["B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB"]; - const UNIT: f64 = 1024.0; - let base = num_bytes.log2() as usize / 10; - let curr_base = UNIT.powi(base as i32) as f64; - let units = num_bytes / curr_base; - let units = (units * 100.0).floor() / 100.0; - let mut once = true; - let mut extra = SmartString::::new(); - write!(extra, "{:.2}", units).unwrap(); - let trimmed = extra - .trim_end_matches(|_| if once { once = false; true } else { false }) - .trim_end_matches("0") - .trim_end_matches("."); - let mut result: SmartString = trimmed.into(); - result.push_str(" "); - result.push_str(SUFFIX[base as usize]); - result - } + ($value:expr) => {{ + use ::core::fmt::Write; + use ::humanize_bytes::smartstring::{LazyCompact, SmartString}; + let mut num_bytes = { $value } as f64; + let mut result = SmartString::::new(); + if num_bytes < 0.0 { + write!(result, "-").unwrap(); + num_bytes = -num_bytes; } - } + + if num_bytes < 1024.0 { + write!(result, "{} B", num_bytes as u16).unwrap(); + result + } else { + const SUFFIX: [&str; 11] = [ + "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB", "RiB", "QiB", + ]; + const UNIT: f64 = 1024.0; + let base = num_bytes.log2() as usize / 10; + let curr_base = UNIT.powi(base as i32) as f64; + let units = num_bytes / curr_base; + let units = (units * 100.0).floor() / 100.0; + let mut once = true; + let mut extra = SmartString::::new(); + write!(extra, "{:.2}", units).unwrap(); + let trimmed = extra + .trim_end_matches(|_| { + if once { + once = false; + true + } else { + false + } + }) + .trim_end_matches("0") + .trim_end_matches("."); + result.push_str(trimmed); + result.push_str(" "); + result.push_str(SUFFIX[base as usize]); + result + } + }}; } pub use humanize_bytes_binary; @@ -100,43 +110,51 @@ mod decimal { /// 1000 (B, kB, MB, GB, TB, PB, EB, ZB, YB) #[macro_export] macro_rules! humanize_bytes_decimal { - ($value:expr) => { - { - use ::humanize_bytes::smartstring::{SmartString, LazyCompact}; - use ::core::fmt::Write; - let num_bytes = { $value } as f64; - if num_bytes <= 0.0 { - "0 B".into() - } else if num_bytes < 1000.0 { - let mut result = SmartString::::new(); - write!(result, "{} B", num_bytes as u16).unwrap(); - result - } else { - const SUFFIX: [&str; 11] = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "RB", "QB"]; - const UNIT: f64 = 1000.0; - let base = num_bytes.log10() as usize / 3; - let curr_base = UNIT.powi(base as i32) as f64; - let units = num_bytes / curr_base; - let units = (units * 100.0).floor() / 100.0; - let mut once = true; - let mut extra = SmartString::::new(); - write!(extra, "{:.2}", units).unwrap(); - let trimmed = extra - .trim_end_matches(|_| if once { once = false; true } else { false }) - .trim_end_matches("0") - .trim_end_matches("."); - let mut result: SmartString = trimmed.into(); - result.push_str(" "); - result.push_str(SUFFIX[base as usize]); - result - } + ($value:expr) => {{ + use ::core::fmt::Write; + use ::humanize_bytes::smartstring::{LazyCompact, SmartString}; + let mut num_bytes = { $value } as f64; + let mut result = SmartString::::new(); + if num_bytes < 0.0 { + write!(result, "-").unwrap(); + num_bytes = -num_bytes; + } + if num_bytes < 1000.0 { + write!(result, "{} B", num_bytes as u16).unwrap(); + result + } else { + const SUFFIX: [&str; 11] = [ + "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB", "RB", "QB", + ]; + const UNIT: f64 = 1000.0; + let base = num_bytes.log10() as usize / 3; + let curr_base = UNIT.powi(base as i32) as f64; + let units = num_bytes / curr_base; + let units = (units * 100.0).floor() / 100.0; + let mut once = true; + let mut extra = SmartString::::new(); + write!(extra, "{:.2}", units).unwrap(); + let trimmed = extra + .trim_end_matches(|_| { + if once { + once = false; + true + } else { + false + } + }) + .trim_end_matches("0") + .trim_end_matches("."); + result.push_str(trimmed); + result.push_str(" "); + result.push_str(SUFFIX[base as usize]); + result } - } + }}; } pub use humanize_bytes_decimal; - /// /// Format a number of bytes as a human-readable string, using the SI decimal suffixes. /// @@ -145,39 +163,46 @@ mod decimal { /// #[macro_export] macro_rules! humanize_quantity { - ($value:expr) => { - { - use ::humanize_bytes::smartstring::{SmartString, LazyCompact}; - use ::core::fmt::Write; - let num_bytes = { $value } as f64; - if num_bytes <= 0.0 { - "0".into() - } else if num_bytes < 1000.0 { - let mut result = SmartString::::new(); - write!(result, "{}", num_bytes as u16).unwrap(); - result - } else { - const SUFFIX: [&str; 11] = ["", "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q"]; - const UNIT: f64 = 1000.0; - let base = num_bytes.log10() as usize / 3; - let curr_base = UNIT.powi(base as i32) as f64; - let units = num_bytes / curr_base; - let units = (units * 100.0).floor() / 100.0; - let mut once = true; - let mut extra = SmartString::::new(); - write!(extra, "{:.2}", units).unwrap(); - let trimmed = extra - .trim_end_matches(|_| if once { once = false; true } else { false }) - .trim_end_matches("0") - .trim_end_matches("."); - let mut result: SmartString = trimmed.into(); - result.push_str(" "); - result.push_str(SUFFIX[base as usize]); - result - } + ($value:expr) => {{ + use ::core::fmt::Write; + use ::humanize_bytes::smartstring::{LazyCompact, SmartString}; + let mut num_bytes = { $value } as f64; + let mut result = SmartString::::new(); + if num_bytes < 0.0 { + write!(result, "-").unwrap(); + num_bytes = -num_bytes; + } + if num_bytes < 1000.0 { + write!(result, "{}", num_bytes as u16).unwrap(); + result + } else { + const SUFFIX: [&str; 11] = ["", "k", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q"]; + const UNIT: f64 = 1000.0; + let base = num_bytes.log10() as usize / 3; + let curr_base = UNIT.powi(base as i32) as f64; + let units = num_bytes / curr_base; + let units = (units * 100.0).floor() / 100.0; + let mut once = true; + let mut extra = SmartString::::new(); + write!(extra, "{:.2}", units).unwrap(); + let trimmed = extra + .trim_end_matches(|_| { + if once { + once = false; + true + } else { + false + } + }) + .trim_end_matches("0") + .trim_end_matches("."); + result.push_str(trimmed); + result.push_str(" "); + result.push_str(SUFFIX[base as usize]); + result } - } + }}; } pub use humanize_quantity; -} \ No newline at end of file +} diff --git a/tests/test.rs b/tests/test.rs index 7756d76..3b77dda 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -1,9 +1,13 @@ #[cfg(test)] mod tests { - use humanize_bytes::{humanize_bytes_binary, humanize_bytes_decimal, humanize_quantity}; + use humanize_bytes::{humanize_bytes_binary, humanize_bytes_decimal, humanize_quantity }; #[test] fn test_humanize_bytes_binary() { + assert_eq!(humanize_bytes_binary!(-(1024 + 103)), "-1.1 KiB"); + assert_eq!(humanize_bytes_binary!(-(1024 + 99)), "-1 KiB"); + assert_eq!(humanize_bytes_binary!(-1), "-1 B"); + assert_eq!(humanize_bytes_binary!(0), "0 B"); assert_eq!(humanize_bytes_binary!(1), "1 B"); assert_eq!(humanize_bytes_binary!(512), "512 B"); @@ -27,6 +31,10 @@ mod tests { #[test] fn test_humanize_bytes_decimal() { + assert_eq!(humanize_bytes_decimal!(-1100), "-1.1 kB"); + assert_eq!(humanize_bytes_decimal!(-1099), "-1 kB"); + assert_eq!(humanize_bytes_decimal!(-1), "-1 B"); + assert_eq!(humanize_bytes_decimal!(0), "0 B"); assert_eq!(humanize_bytes_decimal!(1), "1 B"); assert_eq!(humanize_bytes_decimal!(512), "512 B"); @@ -49,8 +57,12 @@ mod tests { #[test] fn test_humanize_quantity() { + assert_eq!(humanize_quantity!(-1100), "-1.1 k"); + assert_eq!(humanize_quantity!(-1099), "-1 k"); + assert_eq!(humanize_quantity!(-1), "-1"); assert_eq!(humanize_quantity!(0), "0"); assert_eq!(humanize_quantity!(1), "1"); + assert_eq!(humanize_quantity!(512), "512"); assert_eq!(humanize_quantity!(999), "999"); assert_eq!(humanize_quantity!(1000), "1 k");