hf_hub_simple_progress/
lib.rs

1#![cfg_attr(feature = "async-closure", feature(async_fn_traits, unboxed_closures))]
2#![doc = include_str!("../README.md")]
3use serde::{Deserialize, Serialize};
4use std::time::{Duration, Instant};
5
6#[cfg(feature = "sync")]
7pub mod sync;
8
9#[cfg(feature = "async-closure")]
10pub mod async_closure;
11
12/// The download progress event
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ProgressEvent {
15    /// The resource to download
16    pub url: String,
17
18    /// The progress expressed as a value between 0 and 1
19    pub percentage: f32,
20
21    /// Time elapsed since the download as being started
22    pub elapsed_time: Duration,
23
24    /// Estimated time to complete the download
25    pub remaining_time: Duration,
26}
27
28/// Store the state of a download
29#[derive(Debug, Clone)]
30struct DownloadState {
31    start_time: Instant,
32    len: usize,
33    offset: usize,
34    url: String,
35}
36
37impl DownloadState {
38    fn new(len: usize, url: &str) -> DownloadState {
39        DownloadState {
40            start_time: Instant::now(),
41            len,
42            offset: 0,
43            url: url.to_string(),
44        }
45    }
46
47    fn update(&mut self, delta: usize) -> Option<ProgressEvent> {
48        if delta == 0 {
49            return None;
50        }
51
52        self.offset += delta;
53
54        let elapsed_time = Instant::now() - self.start_time;
55
56        let progress = self.offset as f32 / self.len as f32;
57        let progress_100 = progress * 100.;
58
59        let remaining_percentage = 100. - progress_100;
60        let duration_unit = elapsed_time
61            / if progress_100 as u32 == 0 {
62                1
63            } else {
64                progress_100 as u32
65            };
66        let remaining_time = duration_unit * remaining_percentage as u32;
67
68        let event = ProgressEvent {
69            url: self.url.clone(),
70            percentage: progress,
71            elapsed_time,
72            remaining_time,
73        };
74        Some(event)
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use crate::DownloadState;
81    use std::thread::sleep;
82    use std::time::Duration;
83
84    #[test]
85    fn it_works() {
86        let mut state = DownloadState::new(10, "https://www.rust-lang.org");
87
88        assert!(state.update(0).is_none());
89        sleep(Duration::from_secs(1));
90
91        let mid_update = state.update(5).unwrap();
92        assert_eq!(0.5, mid_update.percentage);
93        assert!(mid_update.elapsed_time.as_secs_f32() > 1.);
94        assert!(mid_update.remaining_time.as_secs_f32() > 1.);
95
96        let end_update = state.update(5).unwrap();
97        assert_eq!(1., end_update.percentage);
98        assert_eq!(0., end_update.remaining_time.as_secs_f32());
99    }
100}