mtlog_progress/
iter.rs

1use crate::LogProgressBar;
2
3/// A wrapper around an iterator that displays progress using `LogProgressBar`.
4/// This struct is created by calling `.progress()` or `.progress_with()` on
5/// an iterator.
6pub struct LogProgressIterator<I> {
7    inner: I,
8    progress: LogProgressBar,
9}
10
11impl<I> LogProgressIterator<I> {
12    fn new(inner: I, progress: LogProgressBar) -> Self {
13        Self { inner, progress }
14    }
15}
16
17impl<I: Iterator> Iterator for LogProgressIterator<I> {
18    type Item = I::Item;
19
20    fn next(&mut self) -> Option<Self::Item> {
21        match self.inner.next() {
22            Some(item) => {
23                self.progress.inc(1);
24                Some(item)
25            }
26            None => {
27                self.progress.finish();
28                None
29            }
30        }
31    }
32
33    fn size_hint(&self) -> (usize, Option<usize>) {
34        self.inner.size_hint()
35    }
36}
37
38impl<I: ExactSizeIterator> ExactSizeIterator for LogProgressIterator<I> {
39    fn len(&self) -> usize {
40        self.inner.len()
41    }
42}
43
44impl<I: DoubleEndedIterator> DoubleEndedIterator for LogProgressIterator<I> {
45    fn next_back(&mut self) -> Option<Self::Item> {
46        match self.inner.next_back() {
47            Some(item) => {
48                self.progress.inc(1);
49                Some(item)
50            }
51            None => {
52                self.progress.finish();
53                None
54            }
55        }
56    }
57}
58
59/// Extension trait for wrapping iterators with progress tracking.
60///
61/// This trait is implemented for all iterators and provides the `.progress_with()` method
62/// which requires manually specifying the total length.
63///
64/// # Examples
65///
66/// ```
67/// use mtlog_progress::ProgressIteratorExt;
68///
69/// vec![1, 2, 3, 4, 5]
70///     .into_iter()
71///     .progress_with(5, "Processing items")
72///     .for_each(|item| {
73///         // Work with item
74///     });
75/// ```
76pub trait ProgressIteratorExt: Iterator + Sized {
77    /// Wrap this iterator with progress tracking.
78    ///
79    /// # Arguments
80    ///
81    /// * `len` - The total number of items in the iterator
82    /// * `name` - The name to display for this progress bar
83    ///
84    /// # Examples
85    ///
86    /// ```
87    /// use mtlog_progress::ProgressIteratorExt;
88    ///
89    /// std::iter::repeat(42)
90    ///     .take(100)
91    ///     .progress_with(100, "Repeated values")
92    ///     .for_each(|_| { /* work */ });
93    /// ```
94    fn progress_with(self, len: usize, name: &str) -> LogProgressIterator<Self> {
95        let progress = LogProgressBar::new(len, name);
96        LogProgressIterator::new(self, progress)
97    }
98
99    /// Wrap this `ExactSizeIterator` with automatic length detection.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use mtlog_progress::ProgressIteratorExt;
105    ///
106    /// (0..100)
107    ///     .progress("Counting")
108    ///     .for_each(|n| {
109    ///         // Work with n
110    ///     });
111    /// ```
112    fn progress(self, name: &str) -> LogProgressIterator<Self>
113    where
114        Self: ExactSizeIterator,
115    {
116        let len = self.len();
117        let progress = LogProgressBar::new(len, name);
118        LogProgressIterator::new(self, progress)
119    }
120}
121
122// Blanket implementation for all iterators
123impl<I: Iterator> ProgressIteratorExt for I {}