Skip to main content

provenant/models/
match_score.rs

1use std::fmt;
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
6#[serde(transparent)]
7pub struct MatchScore(f64);
8
9impl MatchScore {
10    pub const MAX: MatchScore = MatchScore(100.0);
11
12    pub const GOOD_THRESHOLD: f64 = 80.0;
13
14    pub fn from_percentage(value: f64) -> Self {
15        MatchScore((value * 100.0).round() / 100.0)
16    }
17
18    pub fn max(self, other: Self) -> Self {
19        if self >= other { self } else { other }
20    }
21
22    pub fn value(self) -> f64 {
23        self.0
24    }
25
26    pub fn is_good(self) -> bool {
27        self.0 >= Self::GOOD_THRESHOLD
28    }
29}
30
31impl fmt::Display for MatchScore {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "{:.2}", self.0)
34    }
35}
36
37impl PartialOrd for MatchScore {
38    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
39        self.0.partial_cmp(&other.0)
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_from_percentage() {
49        let score = MatchScore::from_percentage(95.5);
50        assert!(score.is_good());
51    }
52
53    #[test]
54    fn test_constants() {
55        assert!(MatchScore::MAX.is_good());
56    }
57
58    #[test]
59    fn test_is_good() {
60        assert!(!MatchScore::from_percentage(79.9).is_good());
61        assert!(MatchScore::from_percentage(80.0).is_good());
62        assert!(MatchScore::MAX.is_good());
63    }
64
65    #[test]
66    fn test_serde_roundtrip() {
67        let score = MatchScore::from_percentage(95.5);
68        let json = serde_json::to_string(&score).unwrap();
69        assert_eq!(json, "95.5");
70        let deserialized: MatchScore = serde_json::from_str(&json).unwrap();
71        assert_eq!(score, deserialized);
72    }
73
74    #[test]
75    fn test_display() {
76        assert_eq!(format!("{}", MatchScore::from_percentage(95.5)), "95.50");
77        assert_eq!(format!("{}", MatchScore::MAX), "100.00");
78    }
79
80    #[test]
81    fn test_value() {
82        let score = MatchScore::from_percentage(95.5);
83        assert!((score.value() - 95.5).abs() < 0.01);
84    }
85}