use crate::value::ConfigValue;
use std::collections::HashMap;
pub type EventHandler = Box<dyn Fn(&str, &ConfigValue, Option<&ConfigValue>) + Send + Sync>;
pub struct Emitter {
handlers: HashMap<String, Vec<EventHandler>>,
}
impl Emitter {
pub fn new() -> Self {
Self {
handlers: HashMap::new(),
}
}
pub fn bind(&mut self, event: &str, handler: EventHandler) {
self.handlers
.entry(event.to_string())
.or_default()
.push(handler);
}
pub fn emit(
&self,
event: &str,
key: &str,
value: &ConfigValue,
previous: Option<&ConfigValue>,
) {
let Some(handlers) = self.handlers.get(event) else {
return;
};
for handler in handlers {
handler(key, value, previous);
}
}
pub fn has_handlers(&self, event: &str) -> bool {
self.handlers.get(event).is_some_and(|h| !h.is_empty())
}
}
impl Default for Emitter {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, Mutex};
#[test]
fn test_emit_calls_handlers() {
let mut emitter = Emitter::new();
let log: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(Vec::new()));
let log_clone = log.clone();
emitter.bind(
"changed",
Box::new(move |key, _value, _prev| {
log_clone.lock().unwrap().push(key.to_string());
}),
);
emitter.emit("changed", "server.port", &ConfigValue::Integer(8080), None);
let entries = log.lock().unwrap();
assert_eq!(entries.len(), 1);
assert_eq!(entries[0], "server.port");
}
#[test]
fn test_emit_with_previous_value() {
let mut emitter = Emitter::new();
let saw_previous: Arc<Mutex<bool>> = Arc::new(Mutex::new(false));
let flag = saw_previous.clone();
emitter.bind(
"changed",
Box::new(move |_key, _value, prev| {
if let Some(ConfigValue::Integer(42)) = prev {
*flag.lock().unwrap() = true;
}
}),
);
emitter.emit(
"changed",
"port",
&ConfigValue::Integer(9090),
Some(&ConfigValue::Integer(42)),
);
assert!(*saw_previous.lock().unwrap());
}
#[test]
fn test_emit_no_handlers() {
let emitter = Emitter::new();
emitter.emit("changed", "key", &ConfigValue::Null, None);
}
#[test]
fn test_multiple_handlers() {
let mut emitter = Emitter::new();
let count: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
for _ in 0..3 {
let c = count.clone();
emitter.bind(
"changed",
Box::new(move |_, _, _| {
*c.lock().unwrap() += 1;
}),
);
}
emitter.emit("changed", "key", &ConfigValue::Null, None);
assert_eq!(*count.lock().unwrap(), 3);
}
#[test]
fn test_has_handlers() {
let mut emitter = Emitter::new();
assert!(!emitter.has_handlers("changed"));
emitter.bind("changed", Box::new(|_, _, _| {}));
assert!(emitter.has_handlers("changed"));
assert!(!emitter.has_handlers("other"));
}
}