···
1
1
-
use chrono::DateTime;
2
2
-
use console::Style;
3
3
-
use indicatif::{ProgressBar, ProgressStyle};
4
4
-
use itertools::Itertools;
5
5
-
use std::borrow::Cow;
6
6
-
use std::collections::HashMap;
7
7
-
use std::ops::Range;
8
8
-
use std::sync::{Arc, Mutex};
9
9
-
use std::thread::{self, JoinHandle};
10
10
-
use std::time::{self, Duration};
11
11
-
12
12
-
use crate::Timestamp;
13
13
-
14
14
-
pub const PROGRESS_BARS_STYLE: &str = "\x1b]9;4;1;{percent}\x1b\\{prefix:>12.bold.cyan} {percent:03}% [{bar:25}] {msg:01} ({per_sec}, {elapsed} ago)";
15
15
-
16
16
-
pub struct Spinner {
17
17
-
pub spinner: ProgressBar,
18
18
-
pub finished: Arc<Mutex<bool>>,
19
19
-
pub thread: JoinHandle<()>,
20
20
-
}
21
21
-
22
22
-
impl Spinner {
23
23
-
pub fn start(verb: &'static str, message: &str) -> Self {
24
24
-
let spinner = ProgressBar::new(0).with_style(
25
25
-
ProgressStyle::with_template(&format_log_msg(
26
26
-
Style::new().bold().cyan(),
27
27
-
verb,
28
28
-
&(message.to_owned() + " {spinner:.cyan}"),
29
29
-
))
30
30
-
.unwrap(),
31
31
-
);
32
32
-
spinner.tick();
33
33
-
34
34
-
let thread_spinner = spinner.clone();
35
35
-
let finished = Arc::new(Mutex::new(false));
36
36
-
let thread_finished = Arc::clone(&finished);
37
37
-
let spinner_thread = thread::spawn(move || {
38
38
-
while !*thread_finished.lock().unwrap() {
39
39
-
thread_spinner.tick();
40
40
-
thread::sleep(time::Duration::from_millis(100));
41
41
-
}
42
42
-
thread_spinner.finish_and_clear();
43
43
-
});
44
44
-
45
45
-
Self {
46
46
-
spinner: spinner.clone(),
47
47
-
finished,
48
48
-
thread: spinner_thread,
49
49
-
}
50
50
-
}
51
51
-
52
52
-
pub fn end(self, message: &str) {
53
53
-
self.spinner.finish_and_clear();
54
54
-
*self.finished.lock().unwrap() = true;
55
55
-
self.thread.join().unwrap();
56
56
-
println!("{}", message);
57
57
-
}
58
58
-
}
59
59
-
60
60
-
pub fn setup_progress_bar(total: u64, verb: &'static str) -> ProgressBar {
61
61
-
indicatif::ProgressBar::new(total)
62
62
-
.with_prefix(verb)
63
63
-
.with_style(
64
64
-
indicatif::ProgressStyle::with_template(PROGRESS_BARS_STYLE)
65
65
-
.unwrap()
66
66
-
.progress_chars("=> "),
67
67
-
)
68
68
-
.with_finish(indicatif::ProgressFinish::WithMessage(
69
69
-
"\x1b]9;4;0\x1b\\".into(),
70
70
-
))
71
71
-
}
72
72
-
73
73
-
pub trait Log {
74
74
-
fn log_styled(&self, style: Style, verb: &'static str, message: &str);
75
75
-
fn log(&self, verb: &'static str, message: &str) {
76
76
-
self.log_styled(Style::new().bold().green(), verb, message);
77
77
-
}
78
78
-
fn log_cyan(&self, verb: &'static str, message: &str) {
79
79
-
self.log_styled(Style::new().bold().cyan(), verb, message);
80
80
-
}
81
81
-
fn log_error(&self, verb: &'static str, message: &str) {
82
82
-
self.log_styled(Style::new().bold().red(), verb, message);
83
83
-
}
84
84
-
}
85
85
-
86
86
-
fn format_log_msg(style: Style, verb: &'static str, message: &str) -> String {
87
87
-
format!("{} {}", style.apply_to(format!("{verb:>12}")), message)
88
88
-
}
89
89
-
90
90
-
impl Log for () {
91
91
-
fn log_styled(&self, style: Style, verb: &'static str, message: &str) {
92
92
-
println!("{}", format_log_msg(style, verb, message));
93
93
-
}
94
94
-
}
95
95
-
96
96
-
impl Log for ProgressBar {
97
97
-
fn log_styled(&self, style: Style, verb: &'static str, message: &str) {
98
98
-
self.println(format_log_msg(style, verb, message));
99
99
-
}
100
100
-
}
101
101
-
102
102
-
impl Log for Option<&ProgressBar> {
103
103
-
fn log_styled(&self, style: Style, verb: &'static str, message: &str) {
104
104
-
if let Some(pb) = self {
105
105
-
pb.println(format_log_msg(style, verb, message));
106
106
-
}
107
107
-
}
108
108
-
}
109
109
-
110
110
-
pub trait MaybeProgressBar<'a> {
111
111
-
fn set_message(&'a self, message: impl Into<Cow<'static, str>>);
112
112
-
fn set_length(&'a self, length: u64);
113
113
-
fn inc(&'a self, n: u64);
114
114
-
fn println(&'a self, message: impl AsRef<str>);
115
115
-
}
116
116
-
117
117
-
impl<'a> MaybeProgressBar<'a> for Option<&'a ProgressBar> {
118
118
-
fn set_message(&'a self, message: impl Into<Cow<'static, str>>) {
119
119
-
if let Some(pb) = self {
120
120
-
pb.set_message(message);
121
121
-
}
122
122
-
}
123
123
-
124
124
-
fn set_length(&'a self, length: u64) {
125
125
-
if let Some(pb) = self {
126
126
-
pb.set_length(length);
127
127
-
}
128
128
-
}
129
129
-
130
130
-
fn inc(&'a self, n: u64) {
131
131
-
if let Some(pb) = self {
132
132
-
pb.inc(n);
133
133
-
}
134
134
-
}
135
135
-
136
136
-
fn println(&'a self, message: impl AsRef<str>) {
137
137
-
if let Some(pb) = self {
138
138
-
pb.println(message);
139
139
-
}
140
140
-
}
141
141
-
}
142
142
-
143
143
-
pub(crate) trait Pretty {
144
144
-
fn pretty(&self) -> String;
145
145
-
}
146
146
-
147
147
-
impl<K: std::fmt::Display> Pretty for HashMap<K, usize> {
148
148
-
fn pretty(&self) -> String {
149
149
-
self.iter()
150
150
-
.filter_map(|(name, &count)| {
151
151
-
if count > 0 {
152
152
-
Some(format!("{count} {name}"))
153
153
-
} else {
154
154
-
None
155
155
-
}
156
156
-
})
157
157
-
.join(", ")
158
158
-
}
159
159
-
}
160
160
-
161
161
-
impl Pretty for Duration {
162
162
-
fn pretty(&self) -> String {
163
163
-
let (hours, rest) = self.as_millis().div_rem(&3_600_000);
164
164
-
let (minutes, rest) = rest.div_rem(&60_000);
165
165
-
let (seconds, milliseconds) = rest.div_rem(&1_000);
166
166
-
167
167
-
if hours > 0 {
168
168
-
format!("{} h {:02} m {:02} s", hours, minutes, seconds)
169
169
-
} else if minutes > 0 {
170
170
-
format!("{} m {:02} s", minutes, seconds)
171
171
-
} else if seconds > 0 {
172
172
-
format!("{}.{:03} s", seconds, milliseconds)
173
173
-
} else {
174
174
-
format!("{} ms", milliseconds)
175
175
-
}
176
176
-
}
177
177
-
}
178
178
-
179
179
-
trait DivRem<T> {
180
180
-
fn div_rem(&self, rhs: &T) -> (T, T);
181
181
-
}
182
182
-
183
183
-
impl DivRem<u128> for u128 {
184
184
-
fn div_rem(&self, rhs: &u128) -> (u128, u128) {
185
185
-
(self / rhs, self % rhs)
186
186
-
}
187
187
-
}
188
188
-
189
189
-
impl Pretty for Timestamp {
190
190
-
fn pretty(&self) -> String {
191
191
-
format!(
192
192
-
"{}",
193
193
-
DateTime::from_timestamp_millis(self.ms() as i64)
194
194
-
.unwrap()
195
195
-
.format("%H:%M:%S%.3f")
196
196
-
)
197
197
-
}
198
198
-
}
199
199
-
200
200
-
impl Pretty for Range<Timestamp> {
201
201
-
fn pretty(&self) -> String {
202
202
-
format!("from {} to {}", self.start.pretty(), self.end.pretty())
203
203
-
}
204
204
-
}
205
205
-
206
206
-
impl Pretty for std::path::PathBuf {
207
207
-
fn pretty(&self) -> String {
208
208
-
format!(
209
209
-
"{}{}",
210
210
-
if self.is_relative() { "./" } else { "" },
211
211
-
self.to_string_lossy()
212
212
-
)
213
213
-
}
214
214
-
}
···
1
1
+
use console::Style;
2
2
+
use indicatif::ProgressBar;
3
3
+
4
4
+
pub trait Log {
5
5
+
fn log_styled(&self, style: Style, verb: &'static str, message: &str);
6
6
+
fn log(&self, verb: &'static str, message: &str) {
7
7
+
self.log_styled(Style::new().bold().green(), verb, message);
8
8
+
}
9
9
+
fn log_cyan(&self, verb: &'static str, message: &str) {
10
10
+
self.log_styled(Style::new().bold().cyan(), verb, message);
11
11
+
}
12
12
+
fn log_error(&self, verb: &'static str, message: &str) {
13
13
+
self.log_styled(Style::new().bold().red(), verb, message);
14
14
+
}
15
15
+
}
16
16
+
17
17
+
pub(super) fn format_log_msg(
18
18
+
style: Style,
19
19
+
verb: &'static str,
20
20
+
message: &str,
21
21
+
) -> String {
22
22
+
format!("{} {}", style.apply_to(format!("{verb:>12}")), message)
23
23
+
}
24
24
+
25
25
+
impl Log for () {
26
26
+
fn log_styled(&self, style: Style, verb: &'static str, message: &str) {
27
27
+
println!("{}", format_log_msg(style, verb, message));
28
28
+
}
29
29
+
}
30
30
+
31
31
+
impl Log for ProgressBar {
32
32
+
fn log_styled(&self, style: Style, verb: &'static str, message: &str) {
33
33
+
self.println(format_log_msg(style, verb, message));
34
34
+
}
35
35
+
}
36
36
+
37
37
+
impl Log for Option<&ProgressBar> {
38
38
+
fn log_styled(&self, style: Style, verb: &'static str, message: &str) {
39
39
+
if let Some(pb) = self {
40
40
+
pb.println(format_log_msg(style, verb, message));
41
41
+
}
42
42
+
}
43
43
+
}
···
1
1
+
pub mod log;
2
2
+
pub use log::*;
3
3
+
pub mod pretty;
4
4
+
pub(crate) use pretty::*;
5
5
+
pub mod progress;
6
6
+
pub mod spinner;
7
7
+
pub(crate) use progress::*;
···
1
1
+
use chrono::DateTime;
2
2
+
use itertools::Itertools;
3
3
+
use std::collections::HashMap;
4
4
+
use std::ops::Range;
5
5
+
use std::time::Duration;
6
6
+
7
7
+
use crate::Timestamp;
8
8
+
9
9
+
pub(crate) trait Pretty {
10
10
+
fn pretty(&self) -> String;
11
11
+
}
12
12
+
13
13
+
impl<K: std::fmt::Display> Pretty for HashMap<K, usize> {
14
14
+
fn pretty(&self) -> String {
15
15
+
self.iter()
16
16
+
.filter_map(|(name, &count)| {
17
17
+
if count > 0 {
18
18
+
Some(format!("{count} {name}"))
19
19
+
} else {
20
20
+
None
21
21
+
}
22
22
+
})
23
23
+
.join(", ")
24
24
+
}
25
25
+
}
26
26
+
27
27
+
impl Pretty for Duration {
28
28
+
fn pretty(&self) -> String {
29
29
+
let (hours, rest) = self.as_millis().div_rem(&3_600_000);
30
30
+
let (minutes, rest) = rest.div_rem(&60_000);
31
31
+
let (seconds, milliseconds) = rest.div_rem(&1_000);
32
32
+
33
33
+
if hours > 0 {
34
34
+
format!("{} h {:02} m {:02} s", hours, minutes, seconds)
35
35
+
} else if minutes > 0 {
36
36
+
format!("{} m {:02} s", minutes, seconds)
37
37
+
} else if seconds > 0 {
38
38
+
format!("{}.{:03} s", seconds, milliseconds)
39
39
+
} else {
40
40
+
format!("{} ms", milliseconds)
41
41
+
}
42
42
+
}
43
43
+
}
44
44
+
45
45
+
trait DivRem<T> {
46
46
+
fn div_rem(&self, rhs: &T) -> (T, T);
47
47
+
}
48
48
+
49
49
+
impl DivRem<u128> for u128 {
50
50
+
fn div_rem(&self, rhs: &u128) -> (u128, u128) {
51
51
+
(self / rhs, self % rhs)
52
52
+
}
53
53
+
}
54
54
+
55
55
+
impl Pretty for Timestamp {
56
56
+
fn pretty(&self) -> String {
57
57
+
format!(
58
58
+
"{}",
59
59
+
DateTime::from_timestamp_millis(self.ms() as i64)
60
60
+
.unwrap()
61
61
+
.format("%H:%M:%S%.3f")
62
62
+
)
63
63
+
}
64
64
+
}
65
65
+
66
66
+
impl Pretty for Range<Timestamp> {
67
67
+
fn pretty(&self) -> String {
68
68
+
format!("from {} to {}", self.start.pretty(), self.end.pretty())
69
69
+
}
70
70
+
}
71
71
+
72
72
+
impl Pretty for std::path::PathBuf {
73
73
+
fn pretty(&self) -> String {
74
74
+
format!(
75
75
+
"{}{}",
76
76
+
if self.is_relative() { "./" } else { "" },
77
77
+
self.to_string_lossy()
78
78
+
)
79
79
+
}
80
80
+
}
···
1
1
+
use indicatif::ProgressBar;
2
2
+
use std::borrow::Cow;
3
3
+
4
4
+
pub const PROGRESS_BARS_STYLE: &str = "\x1b]9;4;1;{percent}\x1b\\{prefix:>12.bold.cyan} {percent:03}% [{bar:25}] {msg:01} ({per_sec}, {elapsed} ago)";
5
5
+
6
6
+
pub fn setup_progress_bar(total: u64, verb: &'static str) -> ProgressBar {
7
7
+
indicatif::ProgressBar::new(total)
8
8
+
.with_prefix(verb)
9
9
+
.with_style(
10
10
+
indicatif::ProgressStyle::with_template(PROGRESS_BARS_STYLE)
11
11
+
.unwrap()
12
12
+
.progress_chars("=> "),
13
13
+
)
14
14
+
.with_finish(indicatif::ProgressFinish::WithMessage(
15
15
+
"\x1b]9;4;0\x1b\\".into(),
16
16
+
))
17
17
+
}
18
18
+
19
19
+
pub trait MaybeProgressBar<'a> {
20
20
+
fn set_message(&'a self, message: impl Into<Cow<'static, str>>);
21
21
+
fn set_length(&'a self, length: u64);
22
22
+
fn inc(&'a self, n: u64);
23
23
+
fn println(&'a self, message: impl AsRef<str>);
24
24
+
}
25
25
+
26
26
+
impl<'a> MaybeProgressBar<'a> for Option<&'a ProgressBar> {
27
27
+
fn set_message(&'a self, message: impl Into<Cow<'static, str>>) {
28
28
+
if let Some(pb) = self {
29
29
+
pb.set_message(message);
30
30
+
}
31
31
+
}
32
32
+
33
33
+
fn set_length(&'a self, length: u64) {
34
34
+
if let Some(pb) = self {
35
35
+
pb.set_length(length);
36
36
+
}
37
37
+
}
38
38
+
39
39
+
fn inc(&'a self, n: u64) {
40
40
+
if let Some(pb) = self {
41
41
+
pb.inc(n);
42
42
+
}
43
43
+
}
44
44
+
45
45
+
fn println(&'a self, message: impl AsRef<str>) {
46
46
+
if let Some(pb) = self {
47
47
+
pb.println(message);
48
48
+
}
49
49
+
}
50
50
+
}
···
1
1
+
use console::Style;
2
2
+
use indicatif::{ProgressBar, ProgressStyle};
3
3
+
use std::sync::{Arc, Mutex};
4
4
+
use std::thread::{self, JoinHandle};
5
5
+
use std::time;
6
6
+
7
7
+
pub struct Spinner {
8
8
+
pub spinner: ProgressBar,
9
9
+
pub finished: Arc<Mutex<bool>>,
10
10
+
pub thread: JoinHandle<()>,
11
11
+
}
12
12
+
13
13
+
impl Spinner {
14
14
+
pub fn start(verb: &'static str, message: &str) -> Self {
15
15
+
let spinner = ProgressBar::new(0).with_style(
16
16
+
ProgressStyle::with_template(&super::format_log_msg(
17
17
+
Style::new().bold().cyan(),
18
18
+
verb,
19
19
+
&(message.to_owned() + " {spinner:.cyan}"),
20
20
+
))
21
21
+
.unwrap(),
22
22
+
);
23
23
+
spinner.tick();
24
24
+
25
25
+
let thread_spinner = spinner.clone();
26
26
+
let finished = Arc::new(Mutex::new(false));
27
27
+
let thread_finished = Arc::clone(&finished);
28
28
+
let spinner_thread = thread::spawn(move || {
29
29
+
while !*thread_finished.lock().unwrap() {
30
30
+
thread_spinner.tick();
31
31
+
thread::sleep(time::Duration::from_millis(100));
32
32
+
}
33
33
+
thread_spinner.finish_and_clear();
34
34
+
});
35
35
+
36
36
+
Self {
37
37
+
spinner: spinner.clone(),
38
38
+
finished,
39
39
+
thread: spinner_thread,
40
40
+
}
41
41
+
}
42
42
+
43
43
+
pub fn end(self, message: &str) {
44
44
+
self.spinner.finish_and_clear();
45
45
+
*self.finished.lock().unwrap() = true;
46
46
+
self.thread.join().unwrap();
47
47
+
println!("{}", message);
48
48
+
}
49
49
+
}