dampen_core/handler/
mod.rs1use std::any::Any;
4use std::collections::{HashMap, HashSet};
5use std::sync::{Arc, RwLock};
6
7#[derive(Clone, Debug)]
9pub struct HandlerRegistry {
10 handlers: Arc<RwLock<HashMap<String, HandlerEntry>>>,
11}
12
13#[derive(Clone)]
15#[allow(clippy::type_complexity)]
16pub enum HandlerEntry {
17 Simple(Arc<dyn Fn(&mut dyn Any) + Send + Sync>),
19
20 WithValue(Arc<dyn Fn(&mut dyn Any, Box<dyn Any>) + Send + Sync>),
22
23 WithCommand(Arc<dyn Fn(&mut dyn Any) -> Box<dyn Any> + Send + Sync>),
25}
26
27impl std::fmt::Debug for HandlerEntry {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 HandlerEntry::Simple(_) => f.write_str("Simple(handler)"),
31 HandlerEntry::WithValue(_) => f.write_str("WithValue(handler)"),
32 HandlerEntry::WithCommand(_) => f.write_str("WithCommand(handler)"),
33 }
34 }
35}
36
37impl HandlerRegistry {
38 pub fn new() -> Self {
40 Self {
41 handlers: Arc::new(RwLock::new(HashMap::new())),
42 }
43 }
44
45 pub fn register_simple<F>(&self, name: &str, handler: F)
47 where
48 F: Fn(&mut dyn Any) + Send + Sync + 'static,
49 {
50 if let Ok(mut handlers) = self.handlers.write() {
51 handlers.insert(name.to_string(), HandlerEntry::Simple(Arc::new(handler)));
52 }
53 }
54
55 pub fn register_with_value<F>(&self, name: &str, handler: F)
57 where
58 F: Fn(&mut dyn Any, Box<dyn Any>) + Send + Sync + 'static,
59 {
60 if let Ok(mut handlers) = self.handlers.write() {
61 handlers.insert(name.to_string(), HandlerEntry::WithValue(Arc::new(handler)));
62 }
63 }
64
65 pub fn register_with_command<F>(&self, name: &str, handler: F)
67 where
68 F: Fn(&mut dyn Any) -> Box<dyn Any> + Send + Sync + 'static,
69 {
70 if let Ok(mut handlers) = self.handlers.write() {
71 handlers.insert(
72 name.to_string(),
73 HandlerEntry::WithCommand(Arc::new(handler)),
74 );
75 }
76 }
77
78 pub fn get(&self, name: &str) -> Option<HandlerEntry> {
80 self.handlers.read().ok()?.get(name).cloned()
81 }
82
83 pub fn dispatch(&self, handler_name: &str, model: &mut dyn Any, value: Option<String>) {
108 if let Some(entry) = self.get(handler_name) {
109 match entry {
110 HandlerEntry::Simple(h) => h(model),
111 HandlerEntry::WithValue(h) => {
112 let val = value.unwrap_or_default();
113 h(model, Box::new(val));
114 }
115 HandlerEntry::WithCommand(h) => {
116 h(model);
117 }
118 }
119 }
120 }
121
122 pub fn dispatch_with_command(
159 &self,
160 handler_name: &str,
161 model: &mut dyn Any,
162 value: Option<String>,
163 ) -> Option<Box<dyn Any>> {
164 if let Some(entry) = self.get(handler_name) {
165 match entry {
166 HandlerEntry::Simple(h) => {
167 h(model);
168 None
169 }
170 HandlerEntry::WithValue(h) => {
171 let val = value.unwrap_or_default();
172 h(model, Box::new(val));
173 None
174 }
175 HandlerEntry::WithCommand(h) => Some(h(model)),
176 }
177 } else {
178 None
179 }
180 }
181
182 pub fn contains(&self, name: &str) -> bool {
184 if let Ok(handlers) = self.handlers.read() {
185 handlers.contains_key(name)
186 } else {
187 false
188 }
189 }
190}
191
192impl Default for HandlerRegistry {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198#[derive(Debug, Clone, PartialEq)]
200pub struct HandlerSignature {
201 pub name: String,
203
204 pub param_type: Option<String>,
206
207 pub returns_command: bool,
209}
210
211#[derive(Debug, Clone)]
213pub struct HandlerCallGraph {
214 dependencies: HashMap<String, Vec<String>>,
216}
217
218impl HandlerCallGraph {
219 pub fn new() -> Self {
221 Self {
222 dependencies: HashMap::new(),
223 }
224 }
225
226 pub fn add_dependency(&mut self, from: &str, to: &str) {
228 self.dependencies
229 .entry(from.to_string())
230 .or_default()
231 .push(to.to_string());
232 }
233
234 pub fn would_create_cycle(&self, from: &str, to: &str) -> bool {
236 let mut visited = HashSet::new();
238 self.can_reach(to, from, &mut visited)
239 }
240
241 fn can_reach(&self, from: &str, to: &str, visited: &mut HashSet<String>) -> bool {
243 if from == to {
244 return true;
245 }
246
247 if visited.contains(from) {
248 return false;
249 }
250
251 visited.insert(from.to_string());
252
253 if let Some(deps) = self.dependencies.get(from) {
254 for dep in deps {
255 if self.can_reach(dep, to, visited) {
256 return true;
257 }
258 }
259 }
260
261 false
262 }
263
264 pub fn dependents_of(&self, handler: &str) -> Vec<String> {
266 self.dependencies
267 .iter()
268 .filter_map(|(k, v)| {
269 if v.contains(&handler.to_string()) {
270 Some(k.clone())
271 } else {
272 None
273 }
274 })
275 .collect()
276 }
277
278 pub fn detect_cycles(&self) -> Option<Vec<String>> {
280 let mut visited = HashSet::new();
281 let mut recursion_stack = HashSet::new();
282 let mut path = Vec::new();
283
284 for handler in self.dependencies.keys() {
285 if !visited.contains(handler) {
286 if let Some(cycle) =
287 self.dfs_detect_cycle(handler, &mut visited, &mut recursion_stack, &mut path)
288 {
289 return Some(cycle);
290 }
291 }
292 }
293
294 None
295 }
296
297 fn dfs_detect_cycle(
298 &self,
299 handler: &str,
300 visited: &mut HashSet<String>,
301 recursion_stack: &mut HashSet<String>,
302 path: &mut Vec<String>,
303 ) -> Option<Vec<String>> {
304 visited.insert(handler.to_string());
305 recursion_stack.insert(handler.to_string());
306 path.push(handler.to_string());
307
308 if let Some(deps) = self.dependencies.get(handler) {
309 for dep in deps {
310 if !visited.contains(dep) {
311 if let Some(cycle) = self.dfs_detect_cycle(dep, visited, recursion_stack, path)
312 {
313 return Some(cycle);
314 }
315 } else if recursion_stack.contains(dep) {
316 if let Some(cycle_start) = path.iter().position(|h| h == dep) {
318 let mut cycle = path[cycle_start..].to_vec();
319 cycle.push(dep.to_string());
320 return Some(cycle);
321 }
322 }
323 }
324 }
325
326 path.pop();
327 recursion_stack.remove(handler);
328 None
329 }
330}
331
332impl Default for HandlerCallGraph {
333 fn default() -> Self {
334 Self::new()
335 }
336}