1use std::time::Instant;
2
3mod default {
4 pub const FILLED: &str = "=";
5 pub const EMPTY: &str = "-";
6 pub const START: &str = "[";
7 pub const END: &str = "]";
8 pub const UNIT: &str = "its";
9}
10
11#[derive(Clone, Debug, Hash)]
12pub struct BarElements {
13 filled: String,
14 empty: String,
15 start: String,
16 end: String,
17 unit: String,
18}
19
20impl Default for BarElements {
21 fn default() -> Self {
22 use default::*;
23 Self {
24 filled: FILLED.to_string(),
25 empty: EMPTY.to_string(),
26 start: START.to_string(),
27 end: END.to_string(),
28 unit: UNIT.to_string(),
29 }
30 }
31}
32
33#[derive(Clone, Debug, Hash)]
40pub struct CustomBar {
41 job_name: String,
42 progress: usize,
43 max_hint: usize,
44 finished: bool,
45 last_iter: Instant,
46 elems: BarElements,
47}
48
49impl CustomBar {
50 pub fn set_name(&mut self, job_name: String) {
51 self.job_name = job_name;
52 }
53}
54
55impl crate::IsBar for CustomBar {
56 fn done(&mut self) {
57 self.finished = true;
58 }
59
60 #[must_use]
61 fn is_done(&self) -> bool {
62 self.finished
63 }
64
65 #[must_use]
66 fn display(&mut self) -> String {
67 let now = Instant::now();
68 let time_fmt = format!("{:.3}", 1f32 / (now - self.last_iter).as_secs_f32());
69 self.last_iter = now;
70
71 let width = crate::utils::term_width().unwrap_or(81) as usize;
73
74 let mut res = String::with_capacity(width);
75
76 let percentage = self.progress * 100 / self.max_hint;
77 let bar_len = width.checked_sub(
78 self.job_name.len() +
79 1 +
80 1 +
81 1 +
83 1 +
84 5 +
85 1 +
86 time_fmt.len() +
87 1 +
88 self.elems.unit.len() + 2 ).unwrap();
90 let bar_finished_len = (bar_len as f32 * percentage as f32 / 100.0) as isize;
91
92 res += "\r";
93 res += &self.job_name;
94 res += " ";
95 res += &self.elems.start;
96 for _ in 0..bar_finished_len {
97 res += &self.elems.filled;
98 }
99 for _ in bar_finished_len as usize..bar_len {
100 res += &self.elems.empty;
101 }
102 res += &self.elems.end;
103 res += &format!("{:>4}%", percentage);
105 res += " ";
106 res += &time_fmt;
107 res += " ";
108 res += &self.elems.unit;
109 res += "/s";
110
111 res
112 }
113
114 #[must_use]
115 fn close_method(&self) -> crate::isbar::BarCloseMethod {
116 crate::isbar::BarCloseMethod::LeaveBehind
117 }
118}
119
120impl crate::subsets::IteratorProgress for CustomBar {
121 fn set_progress(&mut self, progress: usize) {
122 self.progress = progress;
123 }
124
125 fn set_size_hint(&mut self, hint: usize) {
126 self.max_hint = hint;
127 }
128}
129
130pub struct Builder {
138 job_name: String,
139 hint: usize,
140 elems: BarElements,
141}
142
143impl Builder {
144 #[must_use]
146 pub fn new(name: impl ToString) -> Self {
147 Self {
148 job_name: name.to_string(),
149 hint: 100,
150 elems: BarElements {
151 ..Default::default()
152 },
153 }
154 }
155
156 #[must_use]
158 pub fn hint(mut self, hint: usize) -> Self {
159 self.hint = hint;
160 self
161 }
162
163 #[must_use]
165 pub fn elems(mut self, elems: BarElements) -> Self {
166 self.elems = elems;
167 self
168 }
169
170 #[must_use]
172 pub fn filled(mut self, v: impl ToString) -> Self {
173 self.elems.filled = v.to_string();
174 self
175 }
176
177 #[must_use]
179 pub fn empty(mut self, v: impl ToString) -> Self {
180 self.elems.empty = v.to_string();
181 self
182 }
183
184 #[must_use]
186 pub fn start(mut self, v: impl ToString) -> Self {
187 self.elems.start = v.to_string();
188 self
189 }
190
191 #[must_use]
193 pub fn end(mut self, v: impl ToString) -> Self {
194 self.elems.end = v.to_string();
195 self
196 }
197
198 #[must_use]
200 pub fn unit(mut self, v: impl ToString) -> Self {
201 self.elems.unit = v.to_string();
202 self
203 }
204
205 #[must_use]
207 pub fn build(self) -> CustomBar {
208 CustomBar {
209 job_name: self.job_name,
210 max_hint: self.hint,
211 elems: self.elems,
212 progress: 0,
213 last_iter: Instant::now(),
214 finished: false,
215 }
216 }
217}