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 Votes,
37 Disagreements,
40 ConsensusOutcomes,
43}
44
45pub trait Context: Send + Sync {
51 fn has(&self, key: ContextKey) -> bool;
53
54 fn get(&self, key: ContextKey) -> &[Fact];
56
57 fn get_proposals(&self, key: ContextKey) -> &[ProposedFact] {
59 let _ = key;
60 &[]
61 }
62
63 fn count(&self, key: ContextKey) -> usize {
65 self.get(key).len()
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 struct MockContext {
74 facts: std::collections::HashMap<ContextKey, Vec<Fact>>,
75 }
76
77 impl MockContext {
78 fn empty() -> Self {
79 Self {
80 facts: std::collections::HashMap::new(),
81 }
82 }
83 }
84
85 impl Context for MockContext {
86 fn has(&self, key: ContextKey) -> bool {
87 self.facts.get(&key).is_some_and(|v| !v.is_empty())
88 }
89
90 fn get(&self, key: ContextKey) -> &[Fact] {
91 self.facts.get(&key).map_or(&[], Vec::as_slice)
92 }
93 }
94
95 #[test]
96 fn get_proposals_default_returns_empty() {
97 let ctx = MockContext::empty();
98 assert!(ctx.get_proposals(ContextKey::Seeds).is_empty());
99 assert!(ctx.get_proposals(ContextKey::Hypotheses).is_empty());
100 }
101
102 #[test]
103 fn count_default_delegates_to_get() {
104 let ctx = MockContext::empty();
105 assert_eq!(ctx.count(ContextKey::Seeds), 0);
106 }
107
108 #[test]
109 fn has_returns_false_for_empty() {
110 let ctx = MockContext::empty();
111 assert!(!ctx.has(ContextKey::Seeds));
112 }
113
114 #[cfg(feature = "kernel-authority")]
115 #[test]
116 fn count_reflects_facts() {
117 use crate::fact::kernel_authority;
118
119 let mut ctx = MockContext::empty();
120 ctx.facts.insert(
121 ContextKey::Seeds,
122 vec![kernel_authority::new_fact(ContextKey::Seeds, "f1", "a")],
123 );
124 assert_eq!(ctx.count(ContextKey::Seeds), 1);
125 assert!(ctx.has(ContextKey::Seeds));
126 assert!(!ctx.has(ContextKey::Hypotheses));
127 }
128}