summaryrefslogtreecommitdiff
path: root/vendor/indicatif/examples/multi-tree.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/indicatif/examples/multi-tree.rs')
-rw-r--r--vendor/indicatif/examples/multi-tree.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/vendor/indicatif/examples/multi-tree.rs b/vendor/indicatif/examples/multi-tree.rs
new file mode 100644
index 0000000..3435424
--- /dev/null
+++ b/vendor/indicatif/examples/multi-tree.rs
@@ -0,0 +1,189 @@
+use std::fmt::Debug;
+use std::sync::{Arc, Mutex};
+use std::thread;
+use std::time::Duration;
+
+use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
+use once_cell::sync::Lazy;
+use rand::rngs::ThreadRng;
+use rand::{Rng, RngCore};
+
+#[derive(Debug, Clone)]
+enum Action {
+ AddProgressBar(usize),
+ IncProgressBar(usize),
+}
+
+#[derive(Clone, Debug)]
+struct Elem {
+ key: String,
+ index: usize,
+ indent: usize,
+ progress_bar: ProgressBar,
+}
+
+static ELEMENTS: Lazy<[Elem; 9]> = Lazy::new(|| {
+ [
+ Elem {
+ indent: 1,
+ index: 0,
+ progress_bar: ProgressBar::new(32),
+ key: "jumps".to_string(),
+ },
+ Elem {
+ indent: 2,
+ index: 1,
+ progress_bar: ProgressBar::new(32),
+ key: "lazy".to_string(),
+ },
+ Elem {
+ indent: 0,
+ index: 0,
+ progress_bar: ProgressBar::new(32),
+ key: "the".to_string(),
+ },
+ Elem {
+ indent: 3,
+ index: 3,
+ progress_bar: ProgressBar::new(32),
+ key: "dog".to_string(),
+ },
+ Elem {
+ indent: 2,
+ index: 2,
+ progress_bar: ProgressBar::new(32),
+ key: "over".to_string(),
+ },
+ Elem {
+ indent: 2,
+ index: 1,
+ progress_bar: ProgressBar::new(32),
+ key: "brown".to_string(),
+ },
+ Elem {
+ indent: 1,
+ index: 1,
+ progress_bar: ProgressBar::new(32),
+ key: "quick".to_string(),
+ },
+ Elem {
+ indent: 3,
+ index: 5,
+ progress_bar: ProgressBar::new(32),
+ key: "a".to_string(),
+ },
+ Elem {
+ indent: 3,
+ index: 3,
+ progress_bar: ProgressBar::new(32),
+ key: "fox".to_string(),
+ },
+ ]
+});
+
+/// The example implements the tree-like collection of progress bars, where elements are
+/// added on the fly and progress bars get incremented until all elements is added and
+/// all progress bars finished.
+/// On each iteration `get_action` function returns some action, and when the tree gets
+/// complete, the function returns `None`, which finishes the loop.
+fn main() {
+ let mp = Arc::new(MultiProgress::new());
+ let sty_main = ProgressStyle::with_template("{bar:40.green/yellow} {pos:>4}/{len:4}").unwrap();
+ let sty_aux = ProgressStyle::with_template("{spinner:.green} {msg} {pos:>4}/{len:4}").unwrap();
+
+ let pb_main = mp.add(ProgressBar::new(
+ ELEMENTS
+ .iter()
+ .map(|e| e.progress_bar.length().unwrap())
+ .sum(),
+ ));
+ pb_main.set_style(sty_main);
+ for elem in ELEMENTS.iter() {
+ elem.progress_bar.set_style(sty_aux.clone());
+ }
+
+ let tree: Arc<Mutex<Vec<&Elem>>> = Arc::new(Mutex::new(Vec::with_capacity(ELEMENTS.len())));
+ let tree2 = Arc::clone(&tree);
+
+ let mp2 = Arc::clone(&mp);
+ let _ = thread::spawn(move || {
+ let mut rng = ThreadRng::default();
+ pb_main.tick();
+ loop {
+ thread::sleep(Duration::from_millis(15));
+ match get_action(&mut rng, &tree) {
+ None => {
+ // all elements were exhausted
+ pb_main.finish();
+ return;
+ }
+ Some(Action::AddProgressBar(el_idx)) => {
+ let elem = &ELEMENTS[el_idx];
+ let pb = mp2.insert(elem.index + 1, elem.progress_bar.clone());
+ pb.set_message(format!("{} {}", " ".repeat(elem.indent), elem.key));
+ tree.lock().unwrap().insert(elem.index, elem);
+ }
+ Some(Action::IncProgressBar(el_idx)) => {
+ let elem = &tree.lock().unwrap()[el_idx];
+ elem.progress_bar.inc(1);
+ let pos = elem.progress_bar.position();
+ if pos >= elem.progress_bar.length().unwrap() {
+ elem.progress_bar.finish_with_message(format!(
+ "{}{} {}",
+ " ".repeat(elem.indent),
+ "✔",
+ elem.key
+ ));
+ }
+ pb_main.inc(1);
+ }
+ }
+ }
+ })
+ .join();
+
+ println!("===============================");
+ println!("the tree should be the same as:");
+ for elem in tree2.lock().unwrap().iter() {
+ println!("{} {}", " ".repeat(elem.indent), elem.key);
+ }
+}
+
+/// The function guarantees to return the action, that is valid for the current tree.
+fn get_action(rng: &mut dyn RngCore, tree: &Mutex<Vec<&Elem>>) -> Option<Action> {
+ let elem_len = ELEMENTS.len() as u64;
+ let list_len = tree.lock().unwrap().len() as u64;
+ let sum_free = tree
+ .lock()
+ .unwrap()
+ .iter()
+ .map(|e| {
+ let pos = e.progress_bar.position();
+ let len = e.progress_bar.length().unwrap();
+ len - pos
+ })
+ .sum::<u64>();
+
+ if sum_free == 0 && list_len == elem_len {
+ // nothing to do more
+ None
+ } else if sum_free == 0 && list_len < elem_len {
+ // there is no place to make an increment
+ Some(Action::AddProgressBar(tree.lock().unwrap().len()))
+ } else {
+ loop {
+ let list = tree.lock().unwrap();
+ let k = rng.gen_range(0..17);
+ if k == 0 && list_len < elem_len {
+ return Some(Action::AddProgressBar(list.len()));
+ } else {
+ let l = (k % list_len) as usize;
+ let pos = list[l].progress_bar.position();
+ let len = list[l].progress_bar.length();
+ if pos < len.unwrap() {
+ return Some(Action::IncProgressBar(l));
+ }
+ }
+ }
+ }
+}