ffsend_api/pipe/
progress.rs

1use std::cmp::min;
2use std::sync::{Arc, Mutex};
3
4use crate::pipe::{prelude::*, PipeReader, PipeWriter};
5
6pub struct ProgressPipe {
7    /// The current progress.
8    // TODO: use state types in `reporter`?
9    cur: u64,
10
11    /// The total pipe length, being the maximum possible progress.
12    // TODO: use state types in `reporter`?
13    len: u64,
14
15    /// A reporter, to report the progress status to.
16    // TODO: do not make this optional, optionally use this pipe instead
17    reporter: Option<Arc<Mutex<dyn ProgressReporter>>>,
18}
19
20impl ProgressPipe {
21    /// Construct a new progress reporting pipe.
22    pub fn new(cur: u64, len: u64, reporter: Option<Arc<Mutex<dyn ProgressReporter>>>) -> Self {
23        Self { cur, len, reporter }
24    }
25
26    /// Construct a new progress reporting pipe.
27    pub fn zero(len: u64, reporter: Option<Arc<Mutex<dyn ProgressReporter>>>) -> Self {
28        Self::new(0, len, reporter)
29    }
30}
31
32impl Pipe for ProgressPipe {
33    type Reader = ProgressReader;
34    type Writer = ProgressWriter;
35
36    fn pipe(&mut self, input: &[u8]) -> (usize, Option<Vec<u8>>) {
37        // Transparently pipe the data
38        let (len, data) = self.pipe_transparent(input);
39
40        // Update current progress and reporter
41        self.cur = min(self.cur + len as u64, self.len);
42        if let Some(reporter) = self.reporter.as_mut() {
43            let progress = self.cur;
44            let _ = reporter.lock().map(|mut r| r.progress(progress));
45        }
46
47        (len, data)
48    }
49}
50
51pub type ProgressReader = PipeReader<ProgressPipe>;
52pub type ProgressWriter = PipeWriter<ProgressPipe>;
53
54impl PipeLen for ProgressReader {
55    fn len_in(&self) -> usize {
56        self.pipe.len as usize
57    }
58
59    fn len_out(&self) -> usize {
60        self.pipe.len as usize
61    }
62}
63
64impl PipeLen for ProgressWriter {
65    fn len_in(&self) -> usize {
66        self.pipe.len as usize
67    }
68
69    fn len_out(&self) -> usize {
70        self.pipe.len as usize
71    }
72}
73
74/// A progress reporter.
75pub trait ProgressReporter: Send {
76    /// Start the progress with the given total.
77    fn start(&mut self, total: u64);
78
79    /// A progress update.
80    fn progress(&mut self, progress: u64);
81
82    /// Finish the progress.
83    fn finish(&mut self);
84}