···111111 }
112112}
113113114114-/// A reader that tracks progress of bytes read
114114+/// A reader that tracks progress of bytes read. Multiple readers may share
115115+/// the same `ProgressBar` clone to drive a single bar across several input
116116+/// streams (container formats iterate over many files); the bar is advanced
117117+/// via `inc`, which is atomic and relative.
115118pub struct ProgressReader<R> {
116119 inner: R,
117120 bar: Option<ProgressBar>,
118118- total_read: u64,
119121 last_update: Instant,
120122 bytes_since_update: u64,
121123 bytes_per_update: u64,
···126128 ProgressReader {
127129 inner,
128130 bar,
129129- total_read: 0,
130131 last_update: Instant::now(),
131132 bytes_since_update: 0,
132133 bytes_per_update: 8192, // Start with 8KB, will adjust dynamically
···144145 let now = Instant::now();
145146 let elapsed = now.duration_since(self.last_update);
146147147147- // Update the progress
148148- bar.set_position(self.total_read);
148148+ bar.inc(self.bytes_since_update);
149149150150 // Adjust bytes_per_update to target ~100ms between updates
151151 if elapsed < Duration::from_millis(50) {
···161161 }
162162}
163163164164+impl<R> Drop for ProgressReader<R> {
165165+ fn drop(&mut self) {
166166+ if let Some(ref bar) = self.bar
167167+ && self.bytes_since_update > 0
168168+ {
169169+ bar.inc(self.bytes_since_update);
170170+ self.bytes_since_update = 0;
171171+ }
172172+ }
173173+}
174174+164175impl<R: Read> Read for ProgressReader<R> {
165176 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
166177 let bytes_read = self.inner.read(buf)?;
167178 if bytes_read > 0 {
168168- self.total_read += bytes_read as u64;
169179 self.maybe_update_progress(bytes_read as u64);
170180 }
171181 Ok(bytes_read)