lux_lib/
progress.rs

1use std::{borrow::Cow, sync::Arc, time::Duration};
2
3mod private {
4    pub trait HasProgress {}
5}
6
7impl private::HasProgress for () {}
8impl private::HasProgress for MultiProgress {}
9impl private::HasProgress for ProgressBar {}
10
11pub trait HasProgress: private::HasProgress {}
12impl<P: private::HasProgress> HasProgress for P {}
13
14#[derive(Clone)]
15pub enum Progress<T: HasProgress> {
16    NoProgress,
17    Progress(T),
18}
19
20impl<T> Progress<T>
21where
22    T: HasProgress,
23{
24    pub fn map<F, R>(&self, callback: F) -> Progress<R>
25    where
26        F: FnOnce(&T) -> R,
27        R: HasProgress,
28    {
29        if let Progress::Progress(progress) = self {
30            Progress::Progress(callback(progress))
31        } else {
32            Progress::NoProgress
33        }
34    }
35}
36
37// WARNING: Don't implement `Clone` for this.
38pub struct MultiProgress(indicatif::MultiProgress);
39pub struct ProgressBar(indicatif::ProgressBar);
40
41impl MultiProgress {
42    pub fn new() -> Self {
43        Self(indicatif::MultiProgress::new())
44    }
45
46    pub fn new_arc() -> Arc<Progress<MultiProgress>> {
47        Arc::new(Progress::Progress(MultiProgress::new()))
48    }
49
50    pub fn add(&self, bar: ProgressBar) -> ProgressBar {
51        ProgressBar(self.0.insert_from_back(0, bar.0))
52    }
53
54    pub fn new_bar(&self) -> ProgressBar {
55        self.add(ProgressBar::new())
56    }
57
58    pub fn suspend<F, R>(&self, callback: F) -> R
59    where
60        F: FnOnce() -> R,
61    {
62        self.0.suspend(callback)
63    }
64}
65
66impl Default for MultiProgress {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72impl ProgressBar {
73    pub fn new() -> Self {
74        let bar =
75            indicatif::ProgressBar::new_spinner().with_finish(indicatif::ProgressFinish::AndClear);
76        bar.enable_steady_tick(Duration::from_millis(100));
77
78        Self(bar)
79    }
80
81    pub fn into_raw(self) -> indicatif::ProgressBar {
82        self.0
83    }
84
85    pub fn set_message<M>(&self, message: M)
86    where
87        M: Into<Cow<'static, str>>,
88    {
89        self.0.set_message(message)
90    }
91
92    pub fn set_position(&self, position: u64) {
93        self.0.set_position(position)
94    }
95
96    pub fn position(&self) -> u64 {
97        self.0.position()
98    }
99
100    pub fn println<M>(&self, message: M)
101    where
102        M: AsRef<str>,
103    {
104        self.0.println(message)
105    }
106
107    pub fn finish_with_message<M>(&self, message: M)
108    where
109        M: Into<Cow<'static, str>>,
110    {
111        self.0.finish_with_message(message)
112    }
113
114    pub fn finish_and_clear(&self) {
115        self.0.finish_and_clear()
116    }
117}
118
119impl Default for ProgressBar {
120    fn default() -> Self {
121        Self::new()
122    }
123}
124
125impl From<String> for ProgressBar {
126    fn from(message: String) -> Self {
127        Self(Self::new().0.with_message(message))
128    }
129}
130
131impl From<u64> for ProgressBar {
132    fn from(position: u64) -> Self {
133        let new = Self::new();
134        new.set_position(position);
135
136        new
137    }
138}