fs_more/file/
progress.rs

1use std::io::Write;
2
3/// File copying or moving progress.
4///
5/// Primarily used in [`copy_file_with_progress`] and [`move_file_with_progress`].
6///
7///
8/// [`copy_file_with_progress`]: super::copy_file_with_progress
9/// [`move_file_with_progress`]: super::move_file_with_progress
10#[derive(Clone, PartialEq, Eq, Debug)]
11pub struct FileProgress {
12    /// Current number of bytes copied or moved to the destination.
13    pub bytes_finished: u64,
14
15    /// Total number of bytes that must be copied or moved to the destination
16    /// to complete the copy or move operation.
17    ///
18    /// This value is always smaller or at most equal to
19    /// the  [`bytes_finished`][Self::bytes_finished] field.
20    pub bytes_total: u64,
21}
22
23
24/// A file write progress handler that implements `Write` and just passes data through.
25pub(crate) struct ProgressWriter<W: Write, F: FnMut(&FileProgress)> {
26    /// Current file copying or moving progress.
27    progress: FileProgress,
28
29    /// The inner writer.
30    inner: W,
31
32    /// *Minimum* number of bytes required between two progress reports.
33    progress_report_byte_interval: u64,
34
35    /// Current number of bytes written since last progress report.
36    bytes_written_since_last_progress_report: u64,
37
38    /// Progress report handler.
39    handler: F,
40}
41
42impl<W: Write, F: FnMut(&FileProgress)> ProgressWriter<W, F> {
43    /// Initialize a new `ProgressWriter` by providing:
44    /// - a writer,
45    /// - your progress handler,
46    /// - the minimum number of bytes copied between two progress reports, and
47    /// - the total file size in bytes.
48    pub fn new(inner: W, handler: F, progress_update_byte_interval: u64, bytes_total: u64) -> Self {
49        Self {
50            progress: FileProgress {
51                bytes_finished: 0,
52                bytes_total,
53            },
54            inner,
55            progress_report_byte_interval: progress_update_byte_interval,
56            bytes_written_since_last_progress_report: 0,
57            handler,
58        }
59    }
60
61    /// Consumes `self` and returns the inner writer, the last known progress and the progress report closure.
62    pub fn into_inner(self) -> (W, FileProgress, F) {
63        (self.inner, self.progress, self.handler)
64    }
65}
66
67impl<W: Write, F: FnMut(&FileProgress)> Write for ProgressWriter<W, F> {
68    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
69        let inner_write_result = self.inner.write(buf);
70
71        if let Ok(bytes_written) = &inner_write_result {
72            self.progress.bytes_finished += *bytes_written as u64;
73            self.bytes_written_since_last_progress_report += *bytes_written as u64;
74        }
75
76        if self.bytes_written_since_last_progress_report > self.progress_report_byte_interval {
77            (self.handler)(&self.progress);
78            self.bytes_written_since_last_progress_report = 0;
79        }
80
81        inner_write_result
82    }
83
84    fn flush(&mut self) -> std::io::Result<()> {
85        self.inner.flush()
86    }
87}