Skip to main content

lux_lib/
progress.rs

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