Skip to main content

codelens_core/insight/
mod.rs

1//! Code insight analysis — health scoring, hotspot detection, trend tracking.
2
3pub mod estimation;
4pub mod health;
5pub mod hotspot;
6pub mod scoring;
7pub mod trend;
8
9use serde::Serialize;
10use std::fmt;
11
12/// Health grade: A through F.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
14pub enum Grade {
15    A,
16    B,
17    C,
18    D,
19    F,
20}
21
22impl fmt::Display for Grade {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            Grade::A => write!(f, "A"),
26            Grade::B => write!(f, "B"),
27            Grade::C => write!(f, "C"),
28            Grade::D => write!(f, "D"),
29            Grade::F => write!(f, "F"),
30        }
31    }
32}
33
34/// Generic delta between two values.
35#[derive(Debug, Clone, Serialize)]
36pub struct DeltaValue<T: Serialize> {
37    pub from: T,
38    pub to: T,
39    pub delta: T,
40    pub percent: f64,
41}
42
43impl DeltaValue<usize> {
44    pub fn new(from: usize, to: usize) -> Self {
45        let delta = to.saturating_sub(from);
46        let percent = if from > 0 {
47            (to as f64 - from as f64) / from as f64 * 100.0
48        } else if to > 0 {
49            100.0
50        } else {
51            0.0
52        };
53        Self {
54            from,
55            to,
56            delta,
57            percent,
58        }
59    }
60
61    pub fn signed_delta(&self) -> i64 {
62        self.to as i64 - self.from as i64
63    }
64}
65
66impl DeltaValue<f64> {
67    pub fn new_f64(from: f64, to: f64) -> Self {
68        let delta = to - from;
69        let percent = if from.abs() > f64::EPSILON {
70            delta / from * 100.0
71        } else if to.abs() > f64::EPSILON {
72            100.0
73        } else {
74            0.0
75        };
76        Self {
77            from,
78            to,
79            delta,
80            percent,
81        }
82    }
83}
84
85#[cfg(test)]
86mod tests {
87    use super::*;
88
89    #[test]
90    fn test_grade_display() {
91        assert_eq!(Grade::A.to_string(), "A");
92        assert_eq!(Grade::F.to_string(), "F");
93    }
94
95    #[test]
96    fn test_grade_ordering() {
97        assert!(Grade::A < Grade::B);
98        assert!(Grade::B < Grade::F);
99    }
100
101    #[test]
102    fn test_delta_value_increase() {
103        let d = DeltaValue::new(100, 120);
104        assert_eq!(d.delta, 20);
105        assert!((d.percent - 20.0).abs() < 0.01);
106        assert_eq!(d.signed_delta(), 20);
107    }
108
109    #[test]
110    fn test_delta_value_decrease() {
111        let d = DeltaValue::new(100, 80);
112        assert_eq!(d.delta, 0);
113        assert_eq!(d.signed_delta(), -20);
114        assert!((d.percent - (-20.0)).abs() < 0.01);
115    }
116
117    #[test]
118    fn test_delta_value_from_zero() {
119        let d = DeltaValue::new(0, 50);
120        assert!((d.percent - 100.0).abs() < 0.01);
121    }
122
123    #[test]
124    fn test_delta_value_f64() {
125        let d = DeltaValue::new_f64(82.0, 78.0);
126        assert!((d.delta - (-4.0)).abs() < 0.01);
127    }
128}