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