From 25ebb623eb0382acdac6ddd1453172cc244b94a8 Mon Sep 17 00:00:00 2001 From: Ishaan Goel Date: Mon, 30 Sep 2024 20:16:03 +0530 Subject: [PATCH] zung_mini progbar (feat): Added a spinner for the `UnBounded Progbar` Because having a bar on the UnBounded iterators does not make any sense. --- zung_mini/src/lib.rs | 11 ++-- zung_mini/src/progbar/mod.rs | 110 ++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 53 deletions(-) diff --git a/zung_mini/src/lib.rs b/zung_mini/src/lib.rs index d01f1fe..825845e 100644 --- a/zung_mini/src/lib.rs +++ b/zung_mini/src/lib.rs @@ -29,10 +29,7 @@ enum MiniCommands { #[derive(Clone, Subcommand, Debug)] #[command(arg_required_else_help = true)] enum ProgBarCommands { - UnBounded { - #[arg(short, long, default_value_t = String::from("#"))] - bar_style: String, - }, + UnBounded, Bounded { #[arg(long, default_value_t = String::from("["))] delim_start: String, @@ -56,9 +53,9 @@ impl MiniArgs { use std::time::Duration; match command { - ProgBarCommands::UnBounded { bar_style } => { + ProgBarCommands::UnBounded => { // test run UnBounded - for _ in (0..).progbar().bar_style(bar_style) { + for _ in (0..).progbar() { sleep(Duration::from_millis(50)) } } @@ -71,8 +68,8 @@ impl MiniArgs { // test run Bounded for _ in (0..iter_count) .progbar() - .bar_style(bar_style) .with_bounds(delim_start, delim_close) + .bar_style(bar_style) { sleep(Duration::from_millis(50)) } diff --git a/zung_mini/src/progbar/mod.rs b/zung_mini/src/progbar/mod.rs index 248cc81..0c8f793 100644 --- a/zung_mini/src/progbar/mod.rs +++ b/zung_mini/src/progbar/mod.rs @@ -85,6 +85,8 @@ use std::cell::Cell; use std::fmt::{Debug, Display}; use std::io::{self, Write}; +use std::thread; +use std::time::Duration; // `BarStyle` is used to define the appearance of the progress bar. It contains // a single string field that holds the character(s) used to visually represent the progress. @@ -112,7 +114,10 @@ impl Default for BarStyle { /// Internal state of `ProgBar`. UnBounded means the Iterator is never ending. This is the default /// state of the [`ProgBar`]. See [`ProgBar::with_bounds`] method if you want to use a [`Bounded`] /// ProgBar. -pub struct UnBounded; +pub struct UnBounded { + spinner: &'static [char; 10], + spinner_step: Cell, +} /// Internal state of `ProgBar`. Bounded means the size of the Iterator is known. This is /// constructed with [`ProgBar::with_bounds`] method. @@ -120,6 +125,7 @@ pub struct Bounded { len: usize, percentage: Cell, delims: (D, D), + bar: BarStyle, } /// Creates a ProgBar type where the `progbar()` method is called over any iterator. @@ -128,7 +134,6 @@ pub struct ProgBar { iterator: T, step: usize, bound: Bound, - bar: BarStyle, } impl ProgBar { @@ -137,46 +142,15 @@ impl ProgBar { Self { iterator, step: 0, - bound: UnBounded, - bar: BarStyle::default(), + bound: UnBounded { + spinner: &['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'], + spinner_step: Cell::new(0), + }, } } } -impl ProgBar { - /// Sets the style of the progress bar. - /// - /// This method allows customizing the appearance of the progress bar by specifying - /// a type that implements the `BarStyle` trait. The provided `bar` parameter - /// should be a reference to an instance of a type that implements both `Display` - /// and `Debug` traits. - /// - /// # Examples - /// - /// ```no_run - /// - /// use zung_mini::progbar::ProgBarExt; - /// - /// (0..100) - /// .progbar() - /// .bar_style(&String::from("=")) - /// .with_bounds("|", "|") - /// .for_each(|_| { - /// // Do some calculation - /// }); - /// - /// // or - /// - /// for _ in (0..).progbar().bar_style(&"<>") { - /// // Do some calculation - /// } - /// - /// ``` - pub fn bar_style(mut self, bar: impl Display) -> Self { - self.bar = BarStyle::new(bar.to_string()); - self - } -} +impl ProgBar {} trait ProgBarDisplay: Sized { fn display(&self, progress: &ProgBar); @@ -184,8 +158,16 @@ trait ProgBarDisplay: Sized { impl ProgBarDisplay for UnBounded { fn display(&self, progress: &ProgBar) { - print!("{}", progress.bar); + let spinner_step = progress.bound.spinner_step.get(); + progress.bound.spinner_step.set(spinner_step + 1); + if spinner_step > progress.bound.spinner.len() - 2 { + progress.bound.spinner_step.set(0); + } + + print!(" {}\r", progress.bound.spinner[spinner_step]); io::stdout().flush().unwrap(); + + thread::sleep(Duration::from_millis(50)); } } @@ -203,7 +185,7 @@ where "[{:>3}%] {}{}{}{}\r", self.percentage.get(), self.delims.0, - progbar.bar.to_string().repeat(progbar.step), + self.bar.to_string().repeat(progbar.step), " ".repeat(self.len - progbar.step), self.delims.1 ); @@ -262,13 +244,13 @@ where len: self.iterator.len(), percentage: Cell::new(0), delims: (bound_start, bound_end), + bar: BarStyle::default(), }; ProgBar { iterator: self.iterator, step: self.step, bound, - bar: self.bar, } } } @@ -277,6 +259,39 @@ impl ProgBar> where D: Display, { + /// Sets the style of the progress bar. + /// + /// This method allows customizing the appearance of the progress bar by specifying + /// a type that implements the `BarStyle` trait. The provided `bar` parameter + /// should be a reference to an instance of a type that implements both `Display` + /// and `Debug` traits. + /// + /// # Examples + /// + /// ```no_run + /// + /// use zung_mini::progbar::ProgBarExt; + /// + /// (0..100) + /// .progbar() + /// .bar_style(&String::from("=")) + /// .with_bounds("|", "|") + /// .for_each(|_| { + /// // Do some calculation + /// }); + /// + /// // or + /// + /// for _ in (0..).progbar().bar_style(&"<>") { + /// // Do some calculation + /// } + /// + /// ``` + pub fn bar_style(mut self, bar: impl Display) -> ProgBar> { + self.bound.bar = BarStyle::new(bar.to_string()); + self + } + fn calculate_percentage(&self) { self.bound .percentage @@ -403,7 +418,7 @@ mod tests { assert_eq!(progbar.bound.len, 10); assert_eq!(progbar.step, 0); assert_eq!(progbar.bound.percentage.get(), 0); - assert_eq!(progbar.bar.to_string(), "#"); + assert_eq!(progbar.bound.bar.to_string(), "#"); } #[test] @@ -444,15 +459,18 @@ mod tests { #[test] fn test_custom_bar_style() { - let progbar = (0..10).progbar().bar_style("=").with_bounds('[', ']'); - assert_eq!(progbar.bar.to_string(), "="); + let progbar = (0..10).progbar().with_bounds('[', ']').bar_style("="); + assert_eq!(progbar.bound.bar.to_string(), "="); assert_eq!(progbar.bound.len, 10); } #[test] fn test_unbounded_progbar() { - let mut progbar = (0..).progbar().bar_style("-"); - assert_eq!(progbar.bar.to_string(), "-"); + let mut progbar = (0..).progbar(); + assert_eq!( + progbar.bound.spinner, + &['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'] + ); for _ in 0..5 { progbar.next(); }