You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.0 KiB
109 lines
3.0 KiB
use std::fmt; |
|
|
|
use yansi::Color::Blue; |
|
|
|
use crate::format::HorizontalScale; |
|
|
|
#[derive(Debug)] |
|
/// A struct that represents a single match bar of a match bar histogram (a |
|
/// bucket for a term/label). |
|
pub struct MatchBarRow { |
|
pub label: String, |
|
pub count: usize, |
|
} |
|
|
|
impl MatchBarRow { |
|
pub fn new(string: &str) -> Self { |
|
Self { |
|
label: string.to_string(), |
|
count: 0, |
|
} |
|
} |
|
|
|
pub fn inc_if_matches(&mut self, line: &str) { |
|
if line.contains(&self.label) { |
|
self.count += 1; |
|
} |
|
} |
|
} |
|
|
|
#[derive(Debug)] |
|
/// A struct holding data to plot a `MatchBar`: a histogram of the number of |
|
/// occurrences of a set of strings in some input dara. |
|
pub struct MatchBar { |
|
pub vec: Vec<MatchBarRow>, |
|
top_values: usize, |
|
top_length: usize, |
|
} |
|
|
|
impl MatchBar { |
|
/// Creates a Histogram from a vector of `MatchBarRow` elements. |
|
pub fn new(vec: Vec<MatchBarRow>) -> Self { |
|
let mut top_length: usize = 0; |
|
let mut top_values: usize = 0; |
|
for row in &vec { |
|
top_length = top_length.max(row.label.len()); |
|
top_values = top_values.max(row.count); |
|
} |
|
Self { |
|
vec, |
|
top_values, |
|
top_length, |
|
} |
|
} |
|
} |
|
|
|
impl fmt::Display for MatchBar { |
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
let width = f.width().unwrap_or(100); |
|
let horizontal_scale = HorizontalScale::new(self.top_values / width); |
|
let width_count = format!("{}", self.top_values).len(); |
|
writeln!( |
|
f, |
|
"Matches: {}.", |
|
Blue.paint(format!( |
|
"{}", |
|
self.vec.iter().map(|r| r.count).sum::<usize>() |
|
)), |
|
)?; |
|
writeln!(f, "{horizontal_scale}")?; |
|
for row in &self.vec { |
|
writeln!( |
|
f, |
|
"[{label}] [{count}] {bar}", |
|
label = Blue.paint(format!("{:width$}", row.label, width = self.top_length)), |
|
count = horizontal_scale.get_count(row.count, width_count), |
|
bar = horizontal_scale.get_bar(row.count) |
|
)?; |
|
} |
|
Ok(()) |
|
} |
|
} |
|
|
|
#[cfg(test)] |
|
mod tests { |
|
use super::*; |
|
use yansi::Paint; |
|
|
|
#[test] |
|
fn test_matchbar() { |
|
let mut row0 = MatchBarRow::new("label1"); |
|
row0.inc_if_matches("labelN"); |
|
row0.inc_if_matches("label1"); |
|
row0.inc_if_matches("label1"); |
|
row0.inc_if_matches("label11"); |
|
let mut row1 = MatchBarRow::new("label2"); |
|
row1.inc_if_matches("label2"); |
|
let mb = MatchBar::new(vec![row0, row1, MatchBarRow::new("label333")]); |
|
assert_eq!(mb.top_length, 8); |
|
assert_eq!(mb.top_values, 3); |
|
Paint::disable(); |
|
let display = format!("{mb}"); |
|
|
|
assert!(display.contains("[label1 ] [3] ∎∎∎\n")); |
|
assert!(display.contains("[label2 ] [1] ∎\n")); |
|
assert!(display.contains("[label333] [0] \n")); |
|
assert!(display.contains("represents a count of 1")); |
|
assert!(display.contains("Matches: 4")); |
|
} |
|
}
|
|
|