devalang_wasm/engine/events/
mod.rs1use crate::language::syntax::ast::{Statement, Value};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone)]
8pub struct EventHandler {
9 pub event_name: String,
10 pub body: Vec<Statement>,
11 pub once: bool, }
13
14#[derive(Debug, Clone)]
16pub struct EventPayload {
17 pub event_name: String,
18 pub data: HashMap<String, Value>,
19 pub timestamp: f32, }
21
22#[derive(Debug, Clone, Default)]
24pub struct EventRegistry {
25 handlers: HashMap<String, Vec<EventHandler>>,
26 emitted_events: Vec<EventPayload>,
27 executed_once: HashMap<String, usize>, }
29
30impl EventRegistry {
31 pub fn new() -> Self {
32 Self::default()
33 }
34
35 pub fn register_handler(&mut self, handler: EventHandler) {
37 let event_name = handler.event_name.clone();
38 self.handlers
39 .entry(event_name)
40 .or_insert_with(Vec::new)
41 .push(handler);
42 }
43
44 pub fn emit(&mut self, event_name: String, data: HashMap<String, Value>, timestamp: f32) {
46 let payload = EventPayload {
47 event_name,
48 data,
49 timestamp,
50 };
51 self.emitted_events.push(payload);
52 }
53
54 pub fn get_handlers(&self, event_name: &str) -> Vec<EventHandler> {
56 self.handlers.get(event_name).cloned().unwrap_or_default()
57 }
58
59 pub fn get_handlers_matching(&self, pattern: &str) -> Vec<EventHandler> {
61 let mut matching = Vec::new();
62
63 for (event_name, handlers) in &self.handlers {
64 if pattern_matches(pattern, event_name) {
65 matching.extend(handlers.clone());
66 }
67 }
68
69 matching
70 }
71
72 pub fn should_execute_once(&mut self, event_name: &str, handler_index: usize) -> bool {
74 let key = format!("{}:{}", event_name, handler_index);
75
76 if self.executed_once.contains_key(&key) {
77 return false;
78 }
79
80 self.executed_once.insert(key, 1);
81 true
82 }
83
84 pub fn get_emitted_events(&self) -> &[EventPayload] {
86 &self.emitted_events
87 }
88
89 pub fn get_events_by_name(&self, event_name: &str) -> Vec<EventPayload> {
91 self.emitted_events
92 .iter()
93 .filter(|e| e.event_name == event_name)
94 .cloned()
95 .collect()
96 }
97
98 pub fn clear_events(&mut self) {
100 self.emitted_events.clear();
101 self.executed_once.clear();
102 }
103
104 pub fn handler_count(&self, event_name: &str) -> usize {
106 self.handlers.get(event_name).map(|h| h.len()).unwrap_or(0)
107 }
108
109 pub fn remove_handlers(&mut self, event_name: &str) {
111 self.handlers.remove(event_name);
112 }
113}
114
115fn pattern_matches(pattern: &str, event_name: &str) -> bool {
118 if pattern == "*" {
119 return true;
120 }
121
122 if !pattern.contains('*') && !pattern.contains('?') {
123 return pattern == event_name;
124 }
125
126 let mut pattern_chars = pattern.chars().peekable();
128 let mut name_chars = event_name.chars().peekable();
129
130 while pattern_chars.peek().is_some() || name_chars.peek().is_some() {
131 match pattern_chars.peek() {
132 Some('*') => {
133 pattern_chars.next();
134
135 if pattern_chars.peek().is_none() {
137 return true;
138 }
139
140 let remaining_pattern: String = pattern_chars.clone().collect();
142 while name_chars.peek().is_some() {
143 let remaining_name: String = name_chars.clone().collect();
144 if pattern_matches(&remaining_pattern, &remaining_name) {
145 return true;
146 }
147 name_chars.next();
148 }
149 return false;
150 }
151 Some('?') => {
152 pattern_chars.next();
153 if name_chars.next().is_none() {
154 return false;
155 }
156 }
157 Some(p) => {
158 let p = *p;
159 pattern_chars.next();
160 match name_chars.next() {
161 Some(n) if n == p => continue,
162 _ => return false,
163 }
164 }
165 None => {
166 return name_chars.peek().is_none();
167 }
168 }
169 }
170
171 true
172}
173
174pub mod builtin_events {
176 pub const BEAT: &str = "beat";
177 pub const BAR: &str = "bar";
178 pub const START: &str = "start";
179 pub const END: &str = "end";
180 pub const TEMPO_CHANGE: &str = "tempo.change";
181 pub const NOTE_ON: &str = "note.on";
182 pub const NOTE_OFF: &str = "note.off";
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188
189 #[test]
190 fn test_register_and_get_handler() {
191 let mut registry = EventRegistry::new();
192
193 let handler = EventHandler {
194 event_name: "test".to_string(),
195 body: vec![],
196 once: false,
197 };
198
199 registry.register_handler(handler);
200
201 let handlers = registry.get_handlers("test");
202 assert_eq!(handlers.len(), 1);
203 assert_eq!(handlers[0].event_name, "test");
204 }
205
206 #[test]
207 fn test_emit_and_get_events() {
208 let mut registry = EventRegistry::new();
209
210 let mut data = HashMap::new();
211 data.insert("value".to_string(), Value::Number(42.0));
212
213 registry.emit("test".to_string(), data, 0.0);
214
215 let events = registry.get_events_by_name("test");
216 assert_eq!(events.len(), 1);
217 assert_eq!(events[0].event_name, "test");
218 }
219
220 #[test]
221 fn test_pattern_matches() {
222 assert!(pattern_matches("*", "anything"));
223 assert!(pattern_matches("test", "test"));
224 assert!(!pattern_matches("test", "other"));
225 assert!(pattern_matches("test*", "test123"));
226 assert!(pattern_matches("*test", "mytest"));
227 assert!(pattern_matches("te?t", "test"));
228 assert!(!pattern_matches("te?t", "teast"));
229 }
230
231 #[test]
232 fn test_once_handler() {
233 let mut registry = EventRegistry::new();
234
235 assert!(registry.should_execute_once("test", 0));
237
238 assert!(!registry.should_execute_once("test", 0));
240 }
241
242 #[test]
243 fn test_wildcard_handlers() {
244 let mut registry = EventRegistry::new();
245
246 registry.register_handler(EventHandler {
247 event_name: "note.on".to_string(),
248 body: vec![],
249 once: false,
250 });
251
252 registry.register_handler(EventHandler {
253 event_name: "note.off".to_string(),
254 body: vec![],
255 once: false,
256 });
257
258 let handlers = registry.get_handlers_matching("note.*");
259 assert_eq!(handlers.len(), 2);
260 }
261
262 #[test]
263 fn test_clear_events() {
264 let mut registry = EventRegistry::new();
265
266 registry.emit("test".to_string(), HashMap::new(), 0.0);
267 assert_eq!(registry.get_emitted_events().len(), 1);
268
269 registry.clear_events();
270 assert_eq!(registry.get_emitted_events().len(), 0);
271 }
272}