diff options
Diffstat (limited to 'vendor/indicatif/examples/multi-tree.rs')
-rw-r--r-- | vendor/indicatif/examples/multi-tree.rs | 189 |
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)); + } + } + } + } +} |