hypen_engine/dispatch/
action.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct Action {
6 pub name: String,
8
9 pub payload: Option<serde_json::Value>,
11
12 pub sender: Option<String>,
14}
15
16impl Action {
17 pub fn new(name: impl Into<String>) -> Self {
18 Self {
19 name: name.into(),
20 payload: None,
21 sender: None,
22 }
23 }
24
25 pub fn with_payload(mut self, payload: serde_json::Value) -> Self {
26 self.payload = Some(payload);
27 self
28 }
29
30 pub fn with_sender(mut self, sender: impl Into<String>) -> Self {
31 self.sender = Some(sender.into());
32 self
33 }
34}
35
36pub type ActionHandler = Box<dyn Fn(&Action) + Send + Sync>;
38
39pub struct ActionDispatcher {
41 handlers: indexmap::IndexMap<String, ActionHandler>,
43}
44
45impl ActionDispatcher {
46 pub fn new() -> Self {
47 Self {
48 handlers: indexmap::IndexMap::new(),
49 }
50 }
51
52 pub fn on<F>(&mut self, action_name: impl Into<String>, handler: F)
54 where
55 F: Fn(&Action) + Send + Sync + 'static,
56 {
57 self.handlers.insert(action_name.into(), Box::new(handler));
58 }
59
60 pub fn dispatch(&self, action: &Action) -> Result<(), String> {
62 if let Some(handler) = self.handlers.get(&action.name) {
63 handler(action);
64 Ok(())
65 } else {
66 Err(format!("No handler registered for action: {}", action.name))
67 }
68 }
69
70 pub fn has_handler(&self, action_name: &str) -> bool {
72 self.handlers.contains_key(action_name)
73 }
74
75 pub fn remove(&mut self, action_name: &str) {
77 self.handlers.shift_remove(action_name);
78 }
79
80 pub fn clear(&mut self) {
82 self.handlers.clear();
83 }
84}
85
86impl Default for ActionDispatcher {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use std::sync::{Arc, Mutex};
96
97 #[test]
98 fn test_action_dispatch() {
99 let mut dispatcher = ActionDispatcher::new();
100 let called = Arc::new(Mutex::new(false));
101 let called_clone = called.clone();
102
103 dispatcher.on("test", move |_action| {
104 *called_clone.lock().unwrap() = true;
105 });
106
107 let action = Action::new("test");
108 dispatcher.dispatch(&action).unwrap();
109
110 assert!(*called.lock().unwrap());
111 }
112
113 #[test]
114 fn test_missing_handler() {
115 let dispatcher = ActionDispatcher::new();
116 let action = Action::new("unknown");
117 assert!(dispatcher.dispatch(&action).is_err());
118 }
119}