mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-16 12:12:35 -06:00
refactor: use smallvec instead of collect string, explicit formatting, accumulator fold
This commit is contained in:
@@ -1,41 +1,43 @@
|
|||||||
use num_width::NumberWidth;
|
use num_width::NumberWidth;
|
||||||
use std::time::Duration;
|
use smallvec::SmallVec;
|
||||||
|
use std::{iter, time::Duration};
|
||||||
|
|
||||||
|
// Helper to split a duration into a integer, decimal, and unit
|
||||||
|
fn get_value(duration: &Duration) -> (u64, u32, &'static str) {
|
||||||
|
let (int, decimal, unit) = match duration {
|
||||||
|
// if greater than 1 second, return as seconds
|
||||||
|
n if n >= &Duration::from_secs(1) => {
|
||||||
|
let secs = n.as_secs();
|
||||||
|
let decimal = n.as_millis() as u64 % 1000;
|
||||||
|
(secs, decimal as u32, "s")
|
||||||
|
}
|
||||||
|
// if greater than 1 millisecond, return as milliseconds
|
||||||
|
n if n >= &Duration::from_millis(1) => {
|
||||||
|
let ms = n.as_millis() as u64;
|
||||||
|
let decimal = n.as_micros() as u64 % 1000;
|
||||||
|
(ms, decimal as u32, "ms")
|
||||||
|
}
|
||||||
|
// if greater than 1 microsecond, return as microseconds
|
||||||
|
n if n >= &Duration::from_micros(1) => {
|
||||||
|
let us = n.as_micros() as u64;
|
||||||
|
let decimal = n.as_nanos() as u64 % 1000;
|
||||||
|
(us, decimal as u32, "µs")
|
||||||
|
}
|
||||||
|
// otherwise, return as nanoseconds
|
||||||
|
n => {
|
||||||
|
let ns = n.as_nanos() as u64;
|
||||||
|
(ns, 0, "ns")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
(int, decimal, unit)
|
||||||
|
}
|
||||||
|
|
||||||
/// Formats timing data into a vector of strings with proper alignment
|
/// Formats timing data into a vector of strings with proper alignment
|
||||||
pub fn format_timing_display(timing_data: Vec<(String, Duration, Duration)>) -> String {
|
pub fn format_timing_display(timing_data: impl IntoIterator<Item = (String, Duration, Duration)>) -> SmallVec<[String; 12]> {
|
||||||
if timing_data.is_empty() {
|
let mut iter = timing_data.into_iter().peekable();
|
||||||
return String::new();
|
if iter.peek().is_none() {
|
||||||
}
|
return SmallVec::new();
|
||||||
|
|
||||||
// Helper to split a duration into a integer, decimal, and unit
|
|
||||||
fn get_value(duration: &Duration) -> (u64, u32, &'static str) {
|
|
||||||
let (int, decimal, unit) = match duration {
|
|
||||||
// if greater than 1 second, return as seconds
|
|
||||||
n if n >= &Duration::from_secs(1) => {
|
|
||||||
let secs = n.as_secs();
|
|
||||||
let decimal = n.as_millis() as u64 % 1000;
|
|
||||||
(secs, decimal as u32, "s")
|
|
||||||
}
|
|
||||||
// if greater than 1 millisecond, return as milliseconds
|
|
||||||
n if n >= &Duration::from_millis(1) => {
|
|
||||||
let ms = n.as_millis() as u64;
|
|
||||||
let decimal = n.as_micros() as u64 % 1000;
|
|
||||||
(ms, decimal as u32, "ms")
|
|
||||||
}
|
|
||||||
// if greater than 1 microsecond, return as microseconds
|
|
||||||
n if n >= &Duration::from_micros(1) => {
|
|
||||||
let us = n.as_micros() as u64;
|
|
||||||
let decimal = n.as_nanos() as u64 % 1000;
|
|
||||||
(us, decimal as u32, "µs")
|
|
||||||
}
|
|
||||||
// otherwise, return as nanoseconds
|
|
||||||
n => {
|
|
||||||
let ns = n.as_nanos() as u64;
|
|
||||||
(ns, 0, "ns")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(int, decimal, unit)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@@ -48,8 +50,7 @@ pub fn format_timing_display(timing_data: Vec<(String, Duration, Duration)>) ->
|
|||||||
std_unit: &'static str,
|
std_unit: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
let entries = timing_data
|
let mut entries = iter
|
||||||
.iter()
|
|
||||||
.map(|(name, avg, std_dev)| {
|
.map(|(name, avg, std_dev)| {
|
||||||
let (avg_int, avg_decimal, avg_unit) = get_value(&avg);
|
let (avg_int, avg_decimal, avg_unit) = get_value(&avg);
|
||||||
let (std_int, std_decimal, std_unit) = get_value(&std_dev);
|
let (std_int, std_decimal, std_unit) = get_value(&std_dev);
|
||||||
@@ -64,84 +65,38 @@ pub fn format_timing_display(timing_data: Vec<(String, Duration, Duration)>) ->
|
|||||||
std_unit,
|
std_unit,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<SmallVec<[Entry; 12]>>();
|
||||||
|
|
||||||
let max_name_width = entries.iter().map(|e| e.name.len() as usize).max().unwrap_or(0);
|
let (max_name_width, max_avg_int_width, max_avg_decimal_width, max_std_int_width, max_std_decimal_width) = entries
|
||||||
let max_avg_int_width = entries.iter().map(|e| e.avg_int.width() as usize).max().unwrap_or(0);
|
|
||||||
let max_avg_decimal_width = entries
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| e.avg_decimal.width() as usize)
|
.fold((0, 0, 3, 0, 3), |(name_w, avg_int_w, avg_dec_w, std_int_w, std_dec_w), e| {
|
||||||
.max()
|
(
|
||||||
.unwrap_or(0)
|
name_w.max(e.name.len()),
|
||||||
.max(3);
|
avg_int_w.max(e.avg_int.width() as usize),
|
||||||
let max_std_int_width = entries.iter().map(|e| e.std_int.width() as usize).max().unwrap_or(0);
|
avg_dec_w.max(e.avg_decimal.width() as usize),
|
||||||
let max_std_decimal_width = entries
|
std_int_w.max(e.std_int.width() as usize),
|
||||||
.iter()
|
std_dec_w.max(e.std_decimal.width() as usize),
|
||||||
.map(|e| e.std_decimal.width() as usize)
|
)
|
||||||
.max()
|
});
|
||||||
.unwrap_or(0)
|
|
||||||
.max(3);
|
|
||||||
|
|
||||||
let mut output_lines = Vec::new();
|
entries.iter().map(|e| {
|
||||||
|
format!(
|
||||||
// Format each line using the calculated max widths for alignment
|
"{name:max_name_width$} : {avg_int:max_avg_int_width$}.{avg_decimal:<max_avg_decimal_width$}{avg_unit} ± {std_int:max_std_int_width$}.{std_decimal:<max_std_decimal_width$}{std_unit}",
|
||||||
for Entry {
|
// Content
|
||||||
name,
|
name = e.name,
|
||||||
avg_int,
|
avg_int = e.avg_int,
|
||||||
avg_decimal,
|
avg_decimal = e.avg_decimal,
|
||||||
avg_unit,
|
std_int = e.std_int,
|
||||||
std_int,
|
std_decimal = e.std_decimal,
|
||||||
std_decimal,
|
// Units
|
||||||
std_unit,
|
avg_unit = e.avg_unit,
|
||||||
} in entries.iter()
|
std_unit = e.std_unit,
|
||||||
{
|
// Padding
|
||||||
output_lines.push(format!(
|
max_name_width = max_name_width,
|
||||||
"{name:max_name_width$} : {avg_int:max_avg_int_width$}.{avg_decimal:<max_avg_decimal_width$}{avg_unit} ± {std_int:max_std_int_width$}.{std_decimal:<max_std_decimal_width$}{std_unit}"
|
max_avg_int_width = max_avg_int_width,
|
||||||
));
|
max_avg_decimal_width = max_avg_decimal_width,
|
||||||
}
|
max_std_int_width = max_std_int_width,
|
||||||
|
max_std_decimal_width = max_std_decimal_width
|
||||||
output_lines.join("\n")
|
)
|
||||||
}
|
}).collect::<SmallVec<[String; 12]>>()
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_format_timing_display() {
|
|
||||||
let timing_data = vec![
|
|
||||||
("total".to_string(), Duration::from_micros(1234), Duration::from_micros(570)),
|
|
||||||
("input".to_string(), Duration::from_micros(120), Duration::from_micros(45)),
|
|
||||||
("player".to_string(), Duration::from_micros(456), Duration::from_micros(123)),
|
|
||||||
("movement".to_string(), Duration::from_micros(789), Duration::from_micros(234)),
|
|
||||||
("render".to_string(), Duration::from_micros(12), Duration::from_micros(3)),
|
|
||||||
("debug".to_string(), Duration::from_nanos(460), Duration::from_nanos(557)),
|
|
||||||
];
|
|
||||||
|
|
||||||
let result = format_timing_display(timing_data);
|
|
||||||
let lines: Vec<&str> = result.lines().collect();
|
|
||||||
|
|
||||||
// Verify we have the expected number of lines
|
|
||||||
assert_eq!(lines.len(), 6);
|
|
||||||
|
|
||||||
let expected = r#"
|
|
||||||
total : 1.234ms ± 570.0 µs
|
|
||||||
input : 120.0 µs ± 45.0 µs
|
|
||||||
player : 456.0 µs ± 123.0 µs
|
|
||||||
movement : 789.0 µs ± 234.0 µs
|
|
||||||
render : 12.0 µs ± 3.0 µs
|
|
||||||
debug : 460.0 ns ± 557.0 ns
|
|
||||||
"#
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
for (line, expected_line) in lines.iter().zip(expected.lines()) {
|
|
||||||
assert_eq!(*line, expected_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the result for manual inspection
|
|
||||||
println!("Formatted output:");
|
|
||||||
println!("{}", result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ impl SystemTimings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use the formatting module to format the data
|
// Use the formatting module to format the data
|
||||||
crate::systems::formatting::format_timing_display(timing_data)
|
crate::systems::formatting::format_timing_display(timing_data).join("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user