Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix add with overflow panic #408

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ exclude = ["screenshots/*"]

[dependencies]
console = { version = "0.15", default-features = false, features = ["ansi-parsing"] }
futures = "0.3.21"
number_prefix = "0.4"
rayon = { version = "1.1", optional = true }
tokio = { version = "1", optional = true, features = ["fs", "io-util"] }
Expand All @@ -24,7 +25,7 @@ vt100 = { version = "0.15.1", optional = true }
once_cell = "1"
rand = "0.8"
structopt = "0.3"
tokio = { version = "1", features = ["time", "rt"] }
tokio = { version = "1", features = ["macros", "time", "rt", "rt-multi-thread"] }

[features]
default = ["unicode-width", "console/unicode-width"]
Expand Down
60 changes: 60 additions & 0 deletions examples/async-multi-main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! Example of asynchronous multiple progress bars.
//!
//! The child bars are added to the main one. Once a child bar is complete it
//! gets removed from the rendering and the main bar advances by 1 unit.
//!
//! Run with
//!
//! ```not_rust
//! cargo run --example async-multi-main.rs
//! ```
//!
use futures::stream::{self, StreamExt};
use rand::{thread_rng, Rng};
use std::sync::Arc;
use tokio::time::{sleep, Duration};

use indicatif::{MultiProgress, ProgressBar, ProgressStyle};

const MAX_CONCURRENT_ITEMS: usize = 5;

#[tokio::main]
async fn main() {
// Creates a new multi-progress object.
let multi = Arc::new(MultiProgress::new());
let style = ProgressStyle::with_template("{bar:40.green/yellow} {pos:>7}/{len:7}").unwrap();

// Create the main progress bar.
let mut rng = thread_rng();
let items = rng.gen_range(MAX_CONCURRENT_ITEMS..MAX_CONCURRENT_ITEMS * 3);
let main = Arc::new(multi.add(ProgressBar::new(items as u64).with_style(style.clone())));
main.tick();

// Add the child progress bars.
let _pbs = stream::iter(0..items)
.map(|_i| add_bar(main.clone(), multi.clone()))
.buffer_unordered(MAX_CONCURRENT_ITEMS)
.collect::<Vec<_>>()
.await;
main.finish_with_message("done");
}

async fn add_bar(main: Arc<ProgressBar>, multi: Arc<MultiProgress>) {
// Create a child bar and add it to the main one.
let mut rng = thread_rng();
let length: u64 = rng.gen_range(128..1024);
let sleep_ms: u64 = rng.gen_range(5..10);
let style = ProgressStyle::with_template("{bar:40.cyan/blue} {pos:>7}/{len:7}").unwrap();
let pb = multi.add(ProgressBar::new(length).with_style(style.clone()));

// Simulate some work.
for _ in 0..length {
pb.inc(1);
sleep(Duration::from_millis(sleep_ms)).await;
}
// Remove the bar once complete.
pb.finish_and_clear();

// Advance the main progress bar.
main.inc(1);
}
9 changes: 8 additions & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,14 @@ impl AtomicPosition {
let (new, remainder) = ((diff / INTERVAL), (diff % INTERVAL));
// We add `new` to `capacity`, subtract one for returning `true` from here,
// then make sure it does not exceed a maximum of `MAX_BURST`.
capacity = Ord::min(MAX_BURST, capacity + new as u8 - 1);
capacity = Ord::min(
MAX_BURST,
capacity
.checked_add(new as u8)
.unwrap_or_default()
.checked_sub(1)
.unwrap_or_default(),
);

// Then, we just store `capacity` and `prev` atomically for the next iteration
self.capacity.store(capacity, Ordering::Release);
Expand Down