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, pub args: Option<Vec<Value>>,
14}
15
16#[derive(Debug, Clone)]
18pub struct EventPayload {
19 pub event_name: String,
20 pub data: HashMap<String, Value>,
21 pub timestamp: f32, }
23
24#[derive(Debug, Clone, Default)]
26pub struct EventRegistry {
27 handlers: HashMap<String, Vec<EventHandler>>,
28 emitted_events: Vec<EventPayload>,
29 executed_once: HashMap<String, usize>, }
31
32impl EventRegistry {
33 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn register_handler(&mut self, handler: EventHandler) {
39 let event_name = handler.event_name.clone();
40 self.handlers
41 .entry(event_name)
42 .or_insert_with(Vec::new)
43 .push(handler);
44 }
45
46 pub fn emit(&mut self, event_name: String, data: HashMap<String, Value>, timestamp: f32) {
48 let payload = EventPayload {
49 event_name,
50 data,
51 timestamp,
52 };
53 self.emitted_events.push(payload);
54 }
55
56 pub fn get_handlers(&self, event_name: &str) -> Vec<EventHandler> {
58 self.handlers.get(event_name).cloned().unwrap_or_default()
59 }
60
61 pub fn get_handlers_matching(&self, pattern: &str) -> Vec<EventHandler> {
63 let mut matching = Vec::new();
64
65 for (event_name, handlers) in &self.handlers {
66 if pattern_matches(pattern, event_name) {
67 matching.extend(handlers.clone());
68 }
69 }
70
71 matching
72 }
73
74 pub fn should_execute_once(&mut self, event_name: &str, handler_index: usize) -> bool {
76 let key = format!("{}:{}", event_name, handler_index);
77
78 if self.executed_once.contains_key(&key) {
79 return false;
80 }
81
82 self.executed_once.insert(key, 1);
83 true
84 }
85
86 pub fn get_emitted_events(&self) -> &[EventPayload] {
88 &self.emitted_events
89 }
90
91 pub fn get_events_by_name(&self, event_name: &str) -> Vec<EventPayload> {
93 self.emitted_events
94 .iter()
95 .filter(|e| e.event_name == event_name)
96 .cloned()
97 .collect()
98 }
99
100 pub fn clear_events(&mut self) {
102 self.emitted_events.clear();
103 self.executed_once.clear();
104 }
105
106 pub fn handler_count(&self, event_name: &str) -> usize {
108 self.handlers.get(event_name).map(|h| h.len()).unwrap_or(0)
109 }
110
111 pub fn remove_handlers(&mut self, event_name: &str) {
113 self.handlers.remove(event_name);
114 }
115}
116
117fn pattern_matches(pattern: &str, event_name: &str) -> bool {
120 if pattern == "*" {
121 return true;
122 }
123
124 if !pattern.contains('*') && !pattern.contains('?') {
125 return pattern == event_name;
126 }
127
128 let mut pattern_chars = pattern.chars().peekable();
130 let mut name_chars = event_name.chars().peekable();
131
132 while pattern_chars.peek().is_some() || name_chars.peek().is_some() {
133 match pattern_chars.peek() {
134 Some('*') => {
135 pattern_chars.next();
136
137 if pattern_chars.peek().is_none() {
139 return true;
140 }
141
142 let remaining_pattern: String = pattern_chars.clone().collect();
144 while name_chars.peek().is_some() {
145 let remaining_name: String = name_chars.clone().collect();
146 if pattern_matches(&remaining_pattern, &remaining_name) {
147 return true;
148 }
149 name_chars.next();
150 }
151 return false;
152 }
153 Some('?') => {
154 pattern_chars.next();
155 if name_chars.next().is_none() {
156 return false;
157 }
158 }
159 Some(p) => {
160 let p = *p;
161 pattern_chars.next();
162 match name_chars.next() {
163 Some(n) if n == p => continue,
164 _ => return false,
165 }
166 }
167 None => {
168 return name_chars.peek().is_none();
169 }
170 }
171 }
172
173 true
174}
175
176pub mod builtin_events {
178 pub const BEAT: &str = "beat";
179 pub const BAR: &str = "bar";
180 pub const START: &str = "start";
181 pub const END: &str = "end";
182 pub const TEMPO_CHANGE: &str = "tempo.change";
183 pub const NOTE_ON: &str = "note.on";
184 pub const NOTE_OFF: &str = "note.off";
185}
186
187#[cfg(test)]
188#[path = "test_events.rs"]
189mod tests;