hf_hub_simple_progress/
lib.rs1#![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#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ProgressEvent {
15 pub url: String,
17
18 pub percentage: f32,
20
21 pub elapsed_time: Duration,
23
24 pub remaining_time: Duration,
26}
27
28#[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}