tokmd_analysis_types/complexity/
histogram.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct ComplexityHistogram {
14 pub buckets: Vec<u32>,
16 pub counts: Vec<u32>,
18 pub total: u32,
20}
21
22impl ComplexityHistogram {
23 pub fn to_ascii(&self, width: usize) -> String {
31 use std::fmt::Write;
32 let max_count = self.counts.iter().max().copied().unwrap_or(1).max(1);
33 let mut output = String::with_capacity(self.counts.len() * (width + 20));
34 for (i, count) in self.counts.iter().enumerate() {
35 match (self.buckets.get(i), self.buckets.get(i + 1)) {
36 (Some(start), Some(next)) => {
37 let end = next.saturating_sub(1).max(*start);
38 let _ = write!(output, "{:>2}-{:<2} |", start, end);
39 }
40 (Some(start), None) => {
41 let _ = write!(output, "{:>2}+ |", start);
42 }
43 (None, _) => {
44 let _ = write!(output, "{:>2}+ |", 0);
45 }
46 }
47
48 let bar_len = (*count as f64 / max_count as f64 * width as f64) as usize;
49 for _ in 0..bar_len {
50 output.push('\u{2588}');
51 }
52 let _ = writeln!(output, " {}", count);
53 }
54 output
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::ComplexityHistogram;
61
62 #[test]
63 fn complexity_histogram_to_ascii_basic() {
64 let h = ComplexityHistogram {
65 buckets: vec![0, 5, 10],
66 counts: vec![10, 5, 2],
67 total: 17,
68 };
69 let ascii = h.to_ascii(20);
70 assert!(!ascii.is_empty());
71 assert_eq!(ascii.lines().count(), 3);
72 }
73
74 #[test]
75 fn complexity_histogram_to_ascii_empty_counts() {
76 let h = ComplexityHistogram {
77 buckets: vec![0, 5],
78 counts: vec![0, 0],
79 total: 0,
80 };
81 let ascii = h.to_ascii(20);
82 assert!(!ascii.is_empty());
83 }
84
85 #[test]
86 fn complexity_histogram_to_ascii_handles_counts_without_buckets() {
87 let h = ComplexityHistogram {
88 buckets: Vec::new(),
89 counts: vec![3, 1],
90 total: 4,
91 };
92 let ascii = h.to_ascii(10);
93 assert_eq!(ascii.lines().count(), 2);
94 assert!(ascii.lines().all(|line| line.starts_with(" 0+")));
95 }
96
97 #[test]
98 fn complexity_histogram_to_ascii_handles_non_increasing_buckets() {
99 let h = ComplexityHistogram {
100 buckets: vec![5, 0],
101 counts: vec![1, 2],
102 total: 3,
103 };
104 let ascii = h.to_ascii(10);
105 assert!(ascii.lines().next().unwrap().starts_with(" 5-5"));
106 }
107}