From 989321af966513e05d34f9a2460fdab26e9d8143 Mon Sep 17 00:00:00 2001 From: Joel Natividad <1980690+jqnatividad@users.noreply.github.com> Date: Tue, 2 Aug 2022 04:11:34 -0400 Subject: [PATCH] HumanFloatCount for per_sec (#453) --- src/format.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 ++++- src/style.rs | 3 ++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/format.rs b/src/format.rs index a9eede38..cd79d6ca 100644 --- a/src/format.rs +++ b/src/format.rs @@ -34,6 +34,10 @@ pub struct BinaryBytes(pub u64); #[derive(Debug)] pub struct HumanCount(pub u64); +/// Formats counts for human readability using commas for floats +#[derive(Debug)] +pub struct HumanFloatCount(pub f64); + impl fmt::Display for FormattedDuration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut t = self.0.as_secs(); @@ -146,6 +150,32 @@ impl fmt::Display for HumanCount { } } +impl fmt::Display for HumanFloatCount { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use fmt::Write; + + let num = format!("{:.4}", self.0); + let (int_part, frac_part) = match num.split_once('.') { + Some((int_str, fract_str)) => (int_str.to_string(), fract_str), + None => (self.0.trunc().to_string(), ""), + }; + let len = int_part.len(); + for (idx, c) in int_part.chars().enumerate() { + let pos = len - idx - 1; + f.write_char(c)?; + if pos > 0 && pos % 3 == 0 { + f.write_char(',')?; + } + } + let frac_trimmed = frac_part.trim_end_matches('0'); + if !frac_trimmed.is_empty() { + f.write_char('.')?; + f.write_str(frac_trimmed)?; + } + Ok(()) + } +} + #[cfg(test)] mod tests { use super::*; @@ -282,4 +312,29 @@ mod tests { assert_eq!("12,345", format!("{}", HumanCount(12345))); assert_eq!("1,234,567,890", format!("{}", HumanCount(1234567890))); } + + #[test] + fn human_float_count() { + assert_eq!("42", format!("{}", HumanFloatCount(42.0))); + assert_eq!("7,654", format!("{}", HumanFloatCount(7654.0))); + assert_eq!("12,345", format!("{}", HumanFloatCount(12345.0))); + assert_eq!( + "1,234,567,890", + format!("{}", HumanFloatCount(1234567890.0)) + ); + assert_eq!("42.5", format!("{}", HumanFloatCount(42.5))); + assert_eq!("42.5", format!("{}", HumanFloatCount(42.500012345))); + assert_eq!("42.502", format!("{}", HumanFloatCount(42.502012345))); + assert_eq!("7,654.321", format!("{}", HumanFloatCount(7654.321))); + assert_eq!("7,654.321", format!("{}", HumanFloatCount(7654.3210123456))); + assert_eq!("12,345.6789", format!("{}", HumanFloatCount(12345.6789))); + assert_eq!( + "1,234,567,890.1235", + format!("{}", HumanFloatCount(1234567890.1234567)) + ); + assert_eq!( + "1,234,567,890.1234", + format!("{}", HumanFloatCount(1234567890.1234321)) + ); + } } diff --git a/src/lib.rs b/src/lib.rs index 9a3ae551..13a66684 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ //! * [`BinaryBytes`](struct.BinaryBytes.html) for formatting bytes using ISO/IEC prefixes //! * [`HumanDuration`](struct.HumanDuration.html) for formatting durations //! * [`HumanCount`](struct.HumanCount.html) for formatting large counts +//! * [`HumanFloatCount`](struct.HumanFloatCount.html) for formatting large float counts //! //! # Progress Bars and Spinners //! @@ -200,11 +201,12 @@ //! //! ```rust //! # use std::time::Duration; -//! use indicatif::{HumanBytes, HumanCount, HumanDuration}; +//! use indicatif::{HumanBytes, HumanCount, HumanDuration, HumanFloatCount}; //! //! assert_eq!("3.00 MiB", HumanBytes(3*1024*1024).to_string()); //! assert_eq!("8 seconds", HumanDuration(Duration::from_secs(8)).to_string()); //! assert_eq!("33,857,009", HumanCount(33857009).to_string()); +//! assert_eq!("33,857,009.1235", HumanFloatCount(33857009.123456).to_string()); //! ``` //! //! # Feature Flags @@ -231,6 +233,7 @@ mod term_like; pub use crate::draw_target::ProgressDrawTarget; pub use crate::format::{ BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanCount, HumanDuration, + HumanFloatCount, }; #[cfg(feature = "in_memory")] pub use crate::in_memory::InMemoryTerm; diff --git a/src/style.rs b/src/style.rs index 3b1176ab..3f082512 100644 --- a/src/style.rs +++ b/src/style.rs @@ -9,6 +9,7 @@ use unicode_segmentation::UnicodeSegmentation; use crate::format::{ BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanCount, HumanDuration, + HumanFloatCount, }; use crate::state::{ProgressState, TabExpandedString, DEFAULT_TAB_WIDTH}; @@ -300,7 +301,7 @@ impl ProgressStyle { .write_fmt(format_args!("{:#}", HumanDuration(state.elapsed()))) .unwrap(), "per_sec" => buf - .write_fmt(format_args!("{:.4}/s", state.per_sec())) + .write_fmt(format_args!("{}/s", HumanFloatCount(state.per_sec()))) .unwrap(), "bytes_per_sec" => buf .write_fmt(format_args!("{}/s", HumanBytes(state.per_sec() as u64)))