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 {}