1use crate::context::{Context, Value};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum Salience {
10 Low,
12 #[default]
14 Medium,
15 High,
17}
18
19#[derive(Debug, Clone, Copy)]
21pub struct SalienceThresholds {
22 pub low_max: i64,
24 pub high_min: i64,
26}
27
28impl Default for SalienceThresholds {
29 fn default() -> Self {
30 Self {
31 low_max: 2, high_min: 20, }
34 }
35}
36
37impl Salience {
38 pub fn from_context(ctx: &Context, thresholds: SalienceThresholds) -> Self {
45 if let Some(Value::String(s)) = ctx.get("salience") {
47 match s.to_lowercase().as_str() {
48 "low" => return Salience::Low,
49 "medium" => return Salience::Medium,
50 "high" => return Salience::High,
51 _ => {}
52 }
53 }
54
55 if let Some(Value::Number(n)) = ctx.get("consumer_count") {
57 if *n < thresholds.low_max {
58 return Salience::Low;
59 }
60 if *n >= thresholds.high_min {
61 return Salience::High;
62 }
63 return Salience::Medium;
64 }
65
66 Salience::default()
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73
74 fn ctx_with(key: &str, value: Value) -> Context {
75 let mut c = Context::new();
76 c.insert(key, value);
77 c
78 }
79
80 #[test]
81 fn explicit_salience_overrides_count() {
82 let mut c = Context::new();
83 c.insert("consumer_count", Value::Number(100));
84 c.insert("salience", Value::String("low".into()));
85
86 assert_eq!(
87 Salience::from_context(&c, SalienceThresholds::default()),
88 Salience::Low
89 );
90 }
91
92 #[test]
93 fn derives_low_from_small_count() {
94 let c = ctx_with("consumer_count", Value::Number(1));
95 assert_eq!(
96 Salience::from_context(&c, SalienceThresholds::default()),
97 Salience::Low
98 );
99 }
100
101 #[test]
102 fn derives_high_from_large_count() {
103 let c = ctx_with("consumer_count", Value::Number(25));
104 assert_eq!(
105 Salience::from_context(&c, SalienceThresholds::default()),
106 Salience::High
107 );
108 }
109
110 #[test]
111 fn derives_medium_from_middle_count() {
112 let c = ctx_with("consumer_count", Value::Number(5));
113 assert_eq!(
114 Salience::from_context(&c, SalienceThresholds::default()),
115 Salience::Medium
116 );
117 }
118
119 #[test]
120 fn defaults_to_medium_without_count() {
121 let c = Context::new();
122 assert_eq!(
123 Salience::from_context(&c, SalienceThresholds::default()),
124 Salience::Medium
125 );
126 }
127
128 #[test]
129 fn zero_count_is_low() {
130 let c = ctx_with("consumer_count", Value::Number(0));
131 assert_eq!(
132 Salience::from_context(&c, SalienceThresholds::default()),
133 Salience::Low
134 );
135 }
136
137 #[test]
138 fn unknown_salience_string_falls_back() {
139 let mut c = Context::new();
140 c.insert("consumer_count", Value::Number(5));
141 c.insert("salience", Value::String("bogus".into()));
142 assert_eq!(
143 Salience::from_context(&c, SalienceThresholds::default()),
144 Salience::Medium
145 );
146 }
147}