1
//!
2
//! A utility function to easily print progress information for procedures that
3
//! take a fixed number of steps. In particular, avoids writing too many
4
//! progress indications.
5
//!
6

            
7
use std::cell::RefCell;
8
use std::marker::PhantomData;
9
use std::time::Duration;
10
use std::time::Instant;
11

            
12
/// A time-based progress tracker that prints messages at regular intervals.
13
pub struct TimeProgress<T> {
14
    interval: Duration,
15
    last_update: RefCell<Instant>,
16
    message: Box<dyn Fn(T)>,
17
    _marker: PhantomData<T>,
18
}
19

            
20
impl<T> TimeProgress<T> {
21
    /// Create a new time-based progress tracker with a given interval in seconds.
22
9943
    pub fn new<F>(message: F, interval_seconds: u64) -> TimeProgress<T>
23
9943
    where
24
9943
        F: Fn(T) + 'static,
25
    {
26
9943
        TimeProgress {
27
9943
            message: Box::new(message),
28
9943
            interval: Duration::from_secs(interval_seconds),
29
9943
            last_update: RefCell::new(Instant::now()),
30
9943
            _marker: PhantomData,
31
9943
        }
32
9943
    }
33

            
34
    /// Increase the progress with the given amount, prints periodic progress
35
    /// messages based on time intervals.
36
8760628
    pub fn print(&self, object: T) {
37
8760628
        let now = Instant::now();
38
8760628
        let should_print = {
39
8760628
            let last = *self.last_update.borrow();
40
8760628
            now.duration_since(last) >= self.interval
41
        };
42
8760628
        if should_print {
43
7613
            (self.message)(object);
44
7613
            *self.last_update.borrow_mut() = now;
45
8753015
        }
46
8760628
    }
47

            
48
    /// Returns true iff the progress tracker is due for an update.
49
1398
    pub fn is_due(&self) -> bool {
50
1398
        let now = Instant::now();
51
1398
        let last = *self.last_update.borrow();
52
1398
        now.duration_since(last) >= self.interval
53
1398
    }
54
}