ecad_processor/utils/
progress.rs

1use indicatif::{ProgressBar, ProgressStyle};
2use std::time::Duration;
3
4pub struct ProgressReporter {
5    progress_bar: Option<ProgressBar>,
6    silent: bool,
7}
8
9impl ProgressReporter {
10    pub fn new(total: u64, message: &str, silent: bool) -> Self {
11        if silent {
12            Self {
13                progress_bar: None,
14                silent: true,
15            }
16        } else {
17            let pb = ProgressBar::new(total);
18            pb.set_style(
19                ProgressStyle::default_bar()
20                    .template("{msg}\n{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})")
21                    .unwrap()
22                    .progress_chars("#>-"),
23            );
24            pb.set_message(message.to_string());
25            pb.enable_steady_tick(Duration::from_millis(100));
26
27            Self {
28                progress_bar: Some(pb),
29                silent: false,
30            }
31        }
32    }
33
34    pub fn new_spinner(message: &str, silent: bool) -> Self {
35        if silent {
36            Self {
37                progress_bar: None,
38                silent: true,
39            }
40        } else {
41            let pb = ProgressBar::new_spinner();
42            pb.set_style(
43                ProgressStyle::default_spinner()
44                    .template("{spinner:.green} {msg}")
45                    .unwrap(),
46            );
47            pb.set_message(message.to_string());
48            pb.enable_steady_tick(Duration::from_millis(100));
49
50            Self {
51                progress_bar: Some(pb),
52                silent: false,
53            }
54        }
55    }
56
57    pub fn update(&self, current: u64) {
58        if let Some(ref pb) = self.progress_bar {
59            pb.set_position(current);
60        }
61    }
62
63    pub fn increment(&self, delta: u64) {
64        if let Some(ref pb) = self.progress_bar {
65            pb.inc(delta);
66        }
67    }
68
69    pub fn set_message(&self, message: &str) {
70        if let Some(ref pb) = self.progress_bar {
71            pb.set_message(message.to_string());
72        }
73    }
74
75    pub fn finish_with_message(&self, message: &str) {
76        if let Some(ref pb) = self.progress_bar {
77            pb.finish_with_message(message.to_string());
78        }
79    }
80
81    pub fn finish(&self) {
82        if let Some(ref pb) = self.progress_bar {
83            pb.finish();
84        }
85    }
86
87    pub fn println(&self, message: &str) {
88        if !self.silent {
89            if let Some(ref pb) = self.progress_bar {
90                pb.println(message);
91            } else {
92                println!("{}", message);
93            }
94        }
95    }
96}
97
98impl Drop for ProgressReporter {
99    fn drop(&mut self) {
100        if let Some(ref pb) = self.progress_bar {
101            pb.finish();
102        }
103    }
104}
105
106/// Create a multi-progress reporter for concurrent operations
107pub struct MultiProgressReporter {
108    bars: Vec<ProgressBar>,
109    silent: bool,
110}
111
112impl MultiProgressReporter {
113    pub fn new(tasks: Vec<(&str, u64)>, silent: bool) -> Self {
114        if silent {
115            Self {
116                bars: vec![],
117                silent: true,
118            }
119        } else {
120            let bars: Vec<ProgressBar> = tasks
121                .into_iter()
122                .map(|(name, total)| {
123                    let pb = ProgressBar::new(total);
124                    pb.set_style(
125                        ProgressStyle::default_bar()
126                            .template("{prefix:>12} [{bar:40.cyan/blue}] {pos}/{len}")
127                            .unwrap()
128                            .progress_chars("#>-"),
129                    );
130                    pb.set_prefix(name.to_string());
131                    pb
132                })
133                .collect();
134
135            Self {
136                bars,
137                silent: false,
138            }
139        }
140    }
141
142    pub fn get_bar(&self, index: usize) -> Option<&ProgressBar> {
143        if self.silent {
144            None
145        } else {
146            self.bars.get(index)
147        }
148    }
149
150    pub fn finish_all(&self) {
151        for bar in &self.bars {
152            bar.finish();
153        }
154    }
155}