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