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
37pub 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}