allora_runtime/dsl/
pattern_registry.rs1use std::collections::HashMap;
48use std::sync::Arc;
49
50use allora_core::patterns::aggregator::{
51 AggregationStrategy, CompletionCondition, ConcatText, EmitSignal, GroupStore, JsonArray,
52};
53
54pub const STRATEGY_CONCAT_TEXT: &str = "allora.concat_text";
56pub const STRATEGY_JSON_ARRAY: &str = "allora.json_array";
58pub const STRATEGY_EMIT_SIGNAL: &str = "allora.emit_signal";
60
61#[derive(Default, Clone)]
63pub struct PatternRegistry {
64 completions: HashMap<String, Arc<dyn CompletionCondition>>,
65 strategies: HashMap<String, Arc<dyn AggregationStrategy>>,
66 stores: HashMap<String, Arc<dyn GroupStore>>,
67}
68
69impl PatternRegistry {
70 pub fn new() -> Self {
72 Self::default()
73 }
74
75 pub fn with_defaults() -> Self {
78 let mut r = Self::default();
79 r.register_strategy(STRATEGY_CONCAT_TEXT, Arc::new(ConcatText));
80 r.register_strategy(STRATEGY_JSON_ARRAY, Arc::new(JsonArray));
81 r.register_strategy(STRATEGY_EMIT_SIGNAL, Arc::new(EmitSignal));
82 r
83 }
84
85 pub fn register_completion<N: Into<String>>(
88 &mut self,
89 name: N,
90 impl_: Arc<dyn CompletionCondition>,
91 ) {
92 self.completions.insert(name.into(), impl_);
93 }
94
95 pub fn register_strategy<N: Into<String>>(
96 &mut self,
97 name: N,
98 impl_: Arc<dyn AggregationStrategy>,
99 ) {
100 self.strategies.insert(name.into(), impl_);
101 }
102
103 pub fn register_store<N: Into<String>>(&mut self, name: N, impl_: Arc<dyn GroupStore>) {
104 self.stores.insert(name.into(), impl_);
105 }
106
107 pub fn completion(&self, name: &str) -> Option<Arc<dyn CompletionCondition>> {
110 self.completions.get(name).cloned()
111 }
112
113 pub fn strategy(&self, name: &str) -> Option<Arc<dyn AggregationStrategy>> {
114 self.strategies.get(name).cloned()
115 }
116
117 pub fn store(&self, name: &str) -> Option<Arc<dyn GroupStore>> {
118 self.stores.get(name).cloned()
119 }
120
121 pub fn completion_names(&self) -> Vec<&str> {
124 self.completions.keys().map(|s| s.as_str()).collect()
125 }
126 pub fn strategy_names(&self) -> Vec<&str> {
127 self.strategies.keys().map(|s| s.as_str()).collect()
128 }
129 pub fn store_names(&self) -> Vec<&str> {
130 self.stores.keys().map(|s| s.as_str()).collect()
131 }
132}
133
134#[cfg(test)]
139mod tests {
140 use super::*;
141 use allora_core::Message;
142 use std::time::Instant;
143
144 struct CountAtLeast(usize);
145 impl CompletionCondition for CountAtLeast {
146 fn is_complete(&self, group: &[Message], _: Instant) -> bool {
147 group.len() >= self.0
148 }
149 }
150
151 #[test]
152 fn empty_registry_returns_none_for_everything() {
153 let r = PatternRegistry::new();
154 assert!(r.completion("anything").is_none());
155 assert!(r.strategy("anything").is_none());
156 assert!(r.store("anything").is_none());
157 assert!(r.completion_names().is_empty());
158 }
159
160 #[test]
161 fn with_defaults_registers_all_three_built_in_strategies() {
162 let r = PatternRegistry::with_defaults();
163 assert!(r.strategy(STRATEGY_CONCAT_TEXT).is_some());
164 assert!(r.strategy(STRATEGY_JSON_ARRAY).is_some());
165 assert!(r.strategy(STRATEGY_EMIT_SIGNAL).is_some());
166 assert!(r.completion_names().is_empty());
168 assert!(r.store_names().is_empty());
169 }
170
171 #[test]
172 fn register_then_lookup_completion() {
173 let mut r = PatternRegistry::new();
174 r.register_completion("chain.test_quorum", Arc::new(CountAtLeast(3)));
175 let c = r.completion("chain.test_quorum").expect("registered");
176 let g: Vec<Message> = (0..3).map(|_| Message::default()).collect();
177 assert!(c.is_complete(&g, Instant::now()));
178 let g2: Vec<Message> = (0..2).map(|_| Message::default()).collect();
179 assert!(!c.is_complete(&g2, Instant::now()));
180 }
181
182 #[test]
183 fn registration_overwrites_existing_entry() {
184 let mut r = PatternRegistry::new();
185 r.register_completion("k", Arc::new(CountAtLeast(1)));
186 r.register_completion("k", Arc::new(CountAtLeast(99)));
187 let c = r.completion("k").unwrap();
188 let g: Vec<Message> = (0..5).map(|_| Message::default()).collect();
189 assert!(!c.is_complete(&g, Instant::now())); }
191}