codeberg_cli/render/
spinner.rs

1use std::future::Future;
2use std::time::Duration;
3
4use indicatif::{ProgressBar, ProgressStyle};
5
6pub async fn spin_until_ready<F, FO>(future: F) -> FO
7where
8    F: Future<Output = FO>,
9{
10    //     const LOADING: &str = "
11    // x     xxxxx   x   xxxx   xxx  xx  x xxxxx
12    // x     x   x  x x  x   x   x   x x x x
13    // x     x   x xxxxx x   x   x   x x x x  xx
14    // x     x   x x   x x   x   x   x  xx x   x
15    // xxxxx xxxxx x   x xxxx   xxx  x  xx xxxxx
16    //         ";
17    let spinner = ProgressBar::new_spinner();
18    spinner.set_style(ProgressStyle::default_spinner());
19    let result = tokio::select! {
20        _ = spin_endless(&spinner) => { unreachable!("future running indefinitely"); }
21        output = future => { output }
22    };
23    spinner.finish_and_clear();
24    result
25}
26
27async fn spin_endless(spinner: &ProgressBar) -> ! {
28    loop {
29        spinner.tick();
30        tokio::time::sleep(Duration::from_millis(100)).await;
31    }
32}
33
34pub async fn spin_and_try_every_second_for<F, FG, FO>(
35    future: FG,
36    num_tries: usize,
37) -> anyhow::Result<FO>
38where
39    FG: Fn() -> F,
40    F: Future<Output = anyhow::Result<FO>>,
41{
42    let spinner = ProgressBar::new_spinner();
43    spinner.set_style(ProgressStyle::default_spinner());
44    let result = tokio::select! {
45        _ = spin_endless(&spinner) => { unreachable!("future running indefinitely"); }
46        output = try_future_x_times(future, num_tries) => { output }
47    };
48    spinner.finish_and_clear();
49    result
50}
51
52async fn try_future_x_times<F, FG, FO>(future: FG, num_tries: usize) -> anyhow::Result<FO>
53where
54    FG: Fn() -> F,
55    F: Future<Output = anyhow::Result<FO>>,
56{
57    let mut tries = num_tries;
58    loop {
59        tries -= 1;
60        tokio::time::sleep(Duration::from_secs(1)).await;
61        let res = future().await;
62        if res.is_ok() || tries == 0 {
63            return res;
64        }
65    }
66}