Skip to main content

dec_cryptor/
progress_utils.rs

1use std::sync::atomic::{AtomicI32, Ordering};
2use std::io::Write;
3use std::time::Instant;
4
5// ANSI颜色代码
6const RESET: &str = "\u{001B}[0m";
7const BLUE: &str = "\u{001B}[94m";
8const PROGRESS_BAR_LENGTH: usize = 40;
9static LAST_PROGRESS: AtomicI32 = AtomicI32::new(-1);
10
11/// 更新并显示带时间的进度
12pub fn update_progress(total_read: u64, file_size: u64) {
13    // 更新进度
14    let mut progress = (total_read * 100 / file_size) as i32;
15
16    // 获得更好体验...yes!
17    if progress > 98 {
18        progress = 100;
19    }
20
21    // 避免出现多个100进度条
22    if progress == LAST_PROGRESS.load(Ordering::Relaxed) {
23        return;
24    }
25
26    // 预计算单位转换因子以提高性能
27    const KB_FACTOR: f64 = 1024.0;
28    const MB_FACTOR: f64 = 1024.0 * 1024.0;
29    const GB_FACTOR: f64 = 1024.0 * 1024.0 * 1024.0;
30
31    let mut unit = "B";
32    let mut total_units = file_size as f64;
33    let mut read_units = total_read as f64;
34
35    // 获得单位
36    if file_size as f64 >= GB_FACTOR {
37        total_units = file_size as f64 / GB_FACTOR;
38        read_units = total_read as f64 / GB_FACTOR;
39        unit = "GB";
40    } else if file_size as f64 >= MB_FACTOR {
41        total_units = file_size as f64 / MB_FACTOR;
42        read_units = total_read as f64 / MB_FACTOR;
43        unit = "MB";
44    } else if file_size as f64 >= KB_FACTOR {
45        total_units = file_size as f64 / KB_FACTOR;
46        read_units = total_read as f64 / KB_FACTOR;
47        unit = "KB";
48    }
49
50    // 限制进度在0-100之间
51    progress = progress.min(100).max(0);
52    LAST_PROGRESS.store(progress, Ordering::Relaxed);
53    
54    // 计算进度条长度
55    let filled_length = ((progress as f64 / 100.0) * PROGRESS_BAR_LENGTH as f64) as usize;
56    
57    // 构建进度条
58    let mut progress_bar = String::with_capacity(100); // 预分配容量
59    progress_bar.push('[');
60    
61    for i in 1..PROGRESS_BAR_LENGTH {
62        if i < filled_length {
63            progress_bar.push_str(&format!("{}#", BLUE));
64        } else if i == filled_length {
65            if progress < 100 {
66                progress_bar.push_str(&format!("{}>", BLUE));
67            } else {
68                progress_bar.push_str(&format!("{}#{}", BLUE, RESET));
69            }
70        } else {
71            progress_bar.push_str(&format!("{}-", RESET));
72        }
73    }
74
75    progress_bar.push_str(&format!("] {}%", progress));
76    
77    // 输出进度(使用回车而不是换行,使进度在同一行更新)
78    print!("\r{}", progress_bar);
79    if progress < 98 {
80        print!("\t {:.2} : {:.2} {}", read_units, total_units, unit);
81    } else {
82        print!("\t {:.2} : {:.2} {}", total_units, total_units, unit);
83    }
84    std::io::stdout().flush().unwrap();
85    
86    // 100%时添加一个换行
87    if progress == 100 {
88        println!();
89    }
90}
91
92/// 格式化持续时间显示
93pub fn format_duration(duration: std::time::Duration) -> String {
94    let total_secs = duration.as_secs();
95    let hours = total_secs / 3600;
96    let minutes = (total_secs % 3600) / 60;
97    let seconds = total_secs % 60;
98    let millis = duration.subsec_millis();
99    
100    if hours > 0 {
101        format!("{}h {}m {}s", hours, minutes, seconds)
102    } else if minutes > 0 {
103        format!("{}m {}s", minutes, seconds)
104    } else {
105        format!("{}.{:03}s", seconds, millis)
106    }
107}
108
109/// 获取开始时间的便捷函数
110pub fn start_timer() -> Instant {
111    Instant::now()
112}