Skip to content

Commit 356d7ef

Browse files
committed
refactor: switch from custom progress bar to indicatif
Replace the custom progress bar implementation with the indicatif crate, which provides more robust terminal handling and better cross-platform support. Changes: - Add indicatif 0.17 as a dependency - Refactor progress.rs to use indicatif's ProgressBar - Create a new Progress struct for better encapsulation - Update speedtest.rs to use the new Progress API - Maintain backward compatibility with print_progress function The new implementation provides the same visual appearance while benefiting from indicatif's features like proper terminal width handling and better rendering performance.
1 parent 7f838c5 commit 356d7ef

4 files changed

Lines changed: 113 additions & 30 deletions

File tree

Cargo.lock

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ csv = "1.3.0"
2121
serde_json = { version = "1.0", features = ["preserve_order"] }
2222
indexmap = "2.12"
2323
clap_complete = "4.5"
24+
indicatif = "0.17"

src/progress.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1-
use std::io::stdout;
2-
use std::io::Write;
3-
4-
pub fn print_progress(name: &str, curr: u32, max: u32) {
5-
const BAR_LEN: u32 = 30;
6-
let progress_line = ((curr as f32 / max as f32) * BAR_LEN as f32) as u32;
7-
let remaining_line = BAR_LEN - progress_line;
8-
print!(
9-
"\r{:<15} [{}{}]",
10-
name,
11-
(0..progress_line).map(|_| "=").collect::<String>(),
12-
(0..remaining_line).map(|_| "-").collect::<String>(),
13-
);
14-
stdout().flush().expect("error printing progress bar");
1+
use indicatif::{ProgressBar, ProgressStyle};
2+
3+
pub struct Progress {
4+
bar: ProgressBar,
5+
}
6+
7+
impl Progress {
8+
pub fn new(name: &str, max: u32) -> Self {
9+
let bar = ProgressBar::new(max as u64);
10+
bar.set_style(
11+
ProgressStyle::default_bar()
12+
.template("{prefix:<15} [{bar:30}]")
13+
.unwrap()
14+
.progress_chars("=-"),
15+
);
16+
bar.set_prefix(name.to_string());
17+
Progress { bar }
18+
}
19+
20+
pub fn set_position(&self, curr: u32) {
21+
self.bar.set_position(curr as u64);
22+
}
23+
24+
pub fn finish(&self) {
25+
self.bar.finish();
26+
}
1527
}

src/speedtest.rs

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::measurements::format_bytes;
22
use crate::measurements::log_measurements;
33
use crate::measurements::LatencyMeasurement;
44
use crate::measurements::Measurement;
5-
use crate::progress::print_progress;
5+
use crate::progress::Progress;
66
use crate::OutputFormat;
77
use crate::SpeedTestCLIOptions;
88
use log;
@@ -160,18 +160,29 @@ pub fn run_latency_test(
160160
output_format: OutputFormat,
161161
) -> (Vec<f64>, f64) {
162162
let mut measurements: Vec<f64> = Vec::new();
163+
let progress = if output_format == OutputFormat::StdOut {
164+
Some(Progress::new("latency test", nr_latency_tests))
165+
} else {
166+
None
167+
};
168+
163169
for i in 0..nr_latency_tests {
164-
if output_format == OutputFormat::StdOut {
165-
print_progress("latency test", i + 1, nr_latency_tests);
170+
if let Some(ref pb) = progress {
171+
pb.set_position(i + 1);
166172
}
167173
let latency = test_latency(client);
168174
measurements.push(latency);
169175
}
176+
177+
if let Some(pb) = progress {
178+
pb.finish();
179+
}
180+
170181
let avg_latency = measurements.iter().sum::<f64>() / measurements.len() as f64;
171182

172183
if output_format == OutputFormat::StdOut {
173184
println!(
174-
"\nAvg GET request latency {avg_latency:.2} ms (RTT excluding server processing time)\n"
185+
"Avg GET request latency {avg_latency:.2} ms (RTT excluding server processing time)\n"
175186
);
176187
}
177188
(measurements, avg_latency)
@@ -233,13 +244,19 @@ pub fn run_tests(
233244
for payload_size in payload_sizes {
234245
log::debug!("running tests for payload_size {payload_size}");
235246
let start = Instant::now();
247+
248+
let progress = if output_format == OutputFormat::StdOut {
249+
Some(Progress::new(
250+
&format!("{:?} {:<5}", test_type, format_bytes(payload_size)),
251+
nr_tests,
252+
))
253+
} else {
254+
None
255+
};
256+
236257
for i in 0..nr_tests {
237-
if output_format == OutputFormat::StdOut {
238-
print_progress(
239-
&format!("{:?} {:<5}", test_type, format_bytes(payload_size)),
240-
i,
241-
nr_tests,
242-
);
258+
if let Some(ref pb) = progress {
259+
pb.set_position(i);
243260
}
244261
let mbit = test_fn(client, payload_size, output_format);
245262
measurements.push(Measurement {
@@ -248,14 +265,13 @@ pub fn run_tests(
248265
mbit,
249266
});
250267
}
251-
if output_format == OutputFormat::StdOut {
252-
print_progress(
253-
&format!("{:?} {:<5}", test_type, format_bytes(payload_size)),
254-
nr_tests,
255-
nr_tests,
256-
);
268+
269+
if let Some(pb) = progress {
270+
pb.set_position(nr_tests);
271+
pb.finish();
257272
println!()
258273
}
274+
259275
let duration = start.elapsed();
260276

261277
// only check TIME_THRESHOLD if dynamic max payload sizing is not disabled

0 commit comments

Comments
 (0)