1use serde::{Deserialize, Serialize};
10
11use crate::fact::{Fact, ProposedFact};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
15#[cfg_attr(feature = "strum", derive(strum::EnumIter))]
16pub enum ContextKey {
17 Seeds,
19 Hypotheses,
21 Strategies,
23 Constraints,
25 Signals,
27 Competitors,
29 Evaluations,
31 Proposals,
33 Diagnostic,
35}
36
37pub trait Context: Send + Sync {
43 fn has(&self, key: ContextKey) -> bool;
45
46 fn get(&self, key: ContextKey) -> &[Fact];
48
49 fn get_proposals(&self, key: ContextKey) -> &[ProposedFact] {
51 let _ = key;
52 &[]
53 }
54
55 fn count(&self, key: ContextKey) -> usize {
57 self.get(key).len()
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 struct MockContext {
66 facts: std::collections::HashMap<ContextKey, Vec<Fact>>,
67 }
68
69 impl MockContext {
70 fn empty() -> Self {
71 Self {
72 facts: std::collections::HashMap::new(),
73 }
74 }
75 }
76
77 impl Context for MockContext {
78 fn has(&self, key: ContextKey) -> bool {
79 self.facts.get(&key).is_some_and(|v| !v.is_empty())
80 }
81
82 fn get(&self, key: ContextKey) -> &[Fact] {
83 self.facts.get(&key).map_or(&[], Vec::as_slice)
84 }
85 }
86
87 #[test]
88 fn get_proposals_default_returns_empty() {
89 let ctx = MockContext::empty();
90 assert!(ctx.get_proposals(ContextKey::Seeds).is_empty());
91 assert!(ctx.get_proposals(ContextKey::Hypotheses).is_empty());
92 }
93
94 #[test]
95 fn count_default_delegates_to_get() {
96 let ctx = MockContext::empty();
97 assert_eq!(ctx.count(ContextKey::Seeds), 0);
98 }
99
100 #[test]
101 fn has_returns_false_for_empty() {
102 let ctx = MockContext::empty();
103 assert!(!ctx.has(ContextKey::Seeds));
104 }
105
106 #[cfg(feature = "kernel-authority")]
107 #[test]
108 fn count_reflects_facts() {
109 use crate::fact::kernel_authority;
110
111 let mut ctx = MockContext::empty();
112 ctx.facts.insert(
113 ContextKey::Seeds,
114 vec![kernel_authority::new_fact(ContextKey::Seeds, "f1", "a")],
115 );
116 assert_eq!(ctx.count(ContextKey::Seeds), 1);
117 assert!(ctx.has(ContextKey::Seeds));
118 assert!(!ctx.has(ContextKey::Hypotheses));
119 }
120}