Skip to main content

sparrow/streaming/
progress.rs

1//! Progress tracking for streaming tasks.
2//!
3//! Thin wrappers around indicatif for styled progress bars and spinners.
4
5use indicatif::{ProgressBar as IndiBar, ProgressStyle};
6
7/// A styled progress bar for tracking task completion.
8pub struct ProgressBar {
9    bar: IndiBar,
10}
11
12impl ProgressBar {
13    /// Create a new progress bar with the given total steps.
14    pub fn new(total: u64) -> Self {
15        let bar = IndiBar::new(total);
16        bar.set_style(
17            ProgressStyle::default_bar()
18                .template(
19                    "{spinner:.cyan} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}",
20                )
21                .unwrap()
22                .progress_chars("▰▱"),
23        );
24        Self { bar }
25    }
26
27    /// Set the current position.
28    pub fn set_position(&self, pos: u64) {
29        self.bar.set_position(pos);
30    }
31
32    /// Set the status message.
33    pub fn set_message(&self, msg: String) {
34        self.bar.set_message(msg);
35    }
36
37    /// Mark the bar as finished with a message.
38    pub fn finish_with_message(&self, msg: String) {
39        self.bar.finish_with_message(msg);
40    }
41
42    /// Get the inner indicatif bar.
43    pub fn inner(&self) -> &IndiBar {
44        &self.bar
45    }
46
47    /// Add this bar to a MultiProgress and return the bar.
48    pub fn add_to(&self, multi: &indicatif::MultiProgress) -> IndiBar {
49        let bar = multi.add(self.bar.clone());
50        bar
51    }
52}
53
54/// A styled spinner for indeterminate operations.
55pub struct Spinner {
56    spinner: indicatif::ProgressBar,
57}
58
59impl Spinner {
60    /// Create a new spinner with a message.
61    pub fn new(message: &str) -> Self {
62        let spinner = indicatif::ProgressBar::new_spinner();
63        spinner.set_style(
64            ProgressStyle::default_spinner()
65                .template("{spinner:.cyan} {msg}")
66                .unwrap(),
67        );
68        spinner.set_message(message.to_string());
69        Self { spinner }
70    }
71
72    /// Update the spinner message.
73    pub fn set_message(&self, msg: &str) {
74        self.spinner.set_message(msg.to_string());
75    }
76
77    /// Finish the spinner with a completion message.
78    pub fn finish_with_message(&self, msg: &str) {
79        self.spinner.finish_with_message(msg.to_string());
80    }
81
82    /// Get the inner spinner.
83    pub fn inner(&self) -> &indicatif::ProgressBar {
84        &self.spinner
85    }
86}
87
88/// Manages multiple progress bars displayed concurrently.
89pub struct MultiProgress {
90    inner: indicatif::MultiProgress,
91}
92
93impl MultiProgress {
94    /// Create a new MultiProgress.
95    pub fn new() -> Self {
96        Self {
97            inner: indicatif::MultiProgress::new(),
98        }
99    }
100
101    /// Add a spinner child to the multi-progress.
102    pub fn add_spinner(&self, spinner: &Spinner) {
103        self.inner.add(spinner.inner().clone());
104    }
105
106    /// Get the inner indicatif MultiProgress.
107    pub fn inner(&self) -> &indicatif::MultiProgress {
108        &self.inner
109    }
110}
111
112impl Default for MultiProgress {
113    fn default() -> Self {
114        Self::new()
115    }
116}