orchestrator_config/config/
item_select.rs1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6pub struct ItemSelectConfig {
7 pub strategy: SelectionStrategy,
9 #[serde(default, skip_serializing_if = "Option::is_none")]
11 pub metric_var: Option<String>,
12 #[serde(default, skip_serializing_if = "Option::is_none")]
14 pub weights: Option<HashMap<String, f64>>,
15 #[serde(default, skip_serializing_if = "Option::is_none")]
17 pub threshold: Option<f64>,
18 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub store_result: Option<StoreTarget>,
21 #[serde(default)]
23 pub tie_break: TieBreak,
24}
25
26#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
28#[serde(rename_all = "snake_case")]
29pub enum SelectionStrategy {
30 Min,
32 Max,
34 Threshold,
36 Weighted,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
42pub struct StoreTarget {
43 pub namespace: String,
45 pub key: String,
47}
48
49#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
51#[serde(rename_all = "snake_case")]
52pub enum TieBreak {
53 #[default]
55 First,
56 Last,
58 Random,
60}
61
62#[derive(Debug, Clone)]
64pub struct SelectionResult {
65 pub winner_id: String,
67 pub eliminated_ids: Vec<String>,
69 pub winner_vars: HashMap<String, String>,
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_item_select_config_min() {
79 let json = r#"{
80 "strategy": "min",
81 "metric_var": "error_count"
82 }"#;
83 let cfg: ItemSelectConfig =
84 serde_json::from_str(json).expect("deserialize item select config");
85 assert_eq!(cfg.strategy, SelectionStrategy::Min);
86 assert_eq!(cfg.metric_var, Some("error_count".to_string()));
87 assert_eq!(cfg.tie_break, TieBreak::First);
88 }
89
90 #[test]
91 fn test_item_select_config_weighted() {
92 let json = r#"{
93 "strategy": "weighted",
94 "weights": {"quality": 0.7, "speed": 0.3},
95 "tie_break": "random",
96 "store_result": {"namespace": "results", "key": "winner"}
97 }"#;
98 let cfg: ItemSelectConfig =
99 serde_json::from_str(json).expect("deserialize weighted config");
100 assert_eq!(cfg.strategy, SelectionStrategy::Weighted);
101 assert_eq!(cfg.tie_break, TieBreak::Random);
102 assert!(cfg.weights.is_some());
103 assert!(cfg.store_result.is_some());
104 }
105
106 #[test]
107 fn test_selection_strategy_serde() {
108 for s in &["\"min\"", "\"max\"", "\"threshold\"", "\"weighted\""] {
109 let strategy: SelectionStrategy =
110 serde_json::from_str(s).expect("deserialize strategy");
111 let json = serde_json::to_string(&strategy).expect("serialize strategy");
112 assert_eq!(&json, s);
113 }
114 }
115
116 #[test]
117 fn test_tie_break_default() {
118 let tb = TieBreak::default();
119 assert_eq!(tb, TieBreak::First);
120 }
121}