tokmd_analysis_types/
churn.rs1use std::collections::BTreeMap;
7
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct PredictiveChurnReport {
12 pub per_module: BTreeMap<String, ChurnTrend>,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct ChurnTrend {
17 pub slope: f64,
18 pub r2: f64,
19 pub recent_change: i64,
20 pub classification: TrendClass,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case")]
25pub enum TrendClass {
26 Rising,
27 Flat,
28 Falling,
29}
30
31#[cfg(test)]
32mod tests {
33 use super::TrendClass;
34
35 #[test]
36 fn trend_class_serde_roundtrip() -> Result<(), Box<dyn std::error::Error>> {
37 for variant in [TrendClass::Rising, TrendClass::Flat, TrendClass::Falling] {
38 let json = serde_json::to_string(&variant)?;
39 let back: TrendClass = serde_json::from_str(&json)?;
40 assert_eq!(back, variant);
41 }
42 Ok(())
43 }
44
45 #[test]
46 fn trend_class_uses_snake_case() -> Result<(), Box<dyn std::error::Error>> {
47 assert_eq!(serde_json::to_string(&TrendClass::Rising)?, "\"rising\"");
48 Ok(())
49 }
50}