1use std::time::Duration;
2
3pub const SPIN: Duration = Duration::from_millis(80);
4pub const SPINNER: [&str; 10] = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
5pub const ABOUT: &str = "≈";
6
7const LADDER: [char; 8] = ['⡀', '⡄', '⡆', '⡇', '⣇', '⣧', '⣷', '⣿'];
8const TRACK: char = '⣀';
9
10fn clean(fraction: f64) -> f64 {
11 if fraction.is_nan() {
12 0.0
13 } else {
14 fraction.clamp(0.0, 1.0)
15 }
16}
17
18pub fn bar(fraction: f64, cells: usize) -> String {
19 let total = cells * 8;
20 let steps = ((clean(fraction) * total as f64).floor() as usize).min(total);
21 let (full, part) = (steps / 8, steps % 8);
22 let mut text: String = std::iter::repeat_n(LADDER[7], full).collect();
23 if part > 0 {
24 text.push(LADDER[part - 1]);
25 }
26 let used = full + usize::from(part > 0);
27 text.extend(std::iter::repeat_n(TRACK, cells.saturating_sub(used)));
28 text
29}
30
31pub fn percent(fraction: f64) -> u32 {
32 (clean(fraction) * 100.0).floor() as u32
33}
34
35pub fn share(fraction: f64, estimate: bool) -> String {
36 let about = if estimate { ABOUT } else { "" };
37 format!("{about}{}%", percent(fraction))
38}
39
40pub fn spinner(gone: Duration) -> &'static str {
41 let frame = gone.as_nanos() / SPIN.as_nanos();
42 SPINNER[(frame % SPINNER.len() as u128) as usize]
43}