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}