use std::any::TypeId;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use super::handler::{BoxedHandler, CustomHandlerId, HandlerEntry, HandlerOptions};
use super::response::EventResponse;
use super::types::{CustomEvent, DispatchPhase, EventEnvelope, EventMeta};
use super::DispatchResult;
pub struct EventDispatcher {
handlers: Arc<RwLock<HashMap<TypeId, Vec<HandlerEntry>>>>,
pending_removals: Arc<RwLock<Vec<CustomHandlerId>>>,
}
impl EventDispatcher {
pub fn new() -> Self {
Self {
handlers: Arc::new(RwLock::new(HashMap::new())),
pending_removals: Arc::new(RwLock::new(Vec::new())),
}
}
pub fn on<E: CustomEvent>(
&mut self,
handler: impl Fn(&E, &mut EventMeta) -> EventResponse + Send + Sync + 'static,
) -> CustomHandlerId {
self.on_with_options::<E>(handler, HandlerOptions::default())
}
pub fn on_with_options<E: CustomEvent>(
&mut self,
handler: impl Fn(&E, &mut EventMeta) -> EventResponse + Send + Sync + 'static,
options: HandlerOptions,
) -> CustomHandlerId {
let id = CustomHandlerId::new();
let type_id = TypeId::of::<E>();
let boxed: BoxedHandler = Box::new(move |any, meta| {
if let Some(event) = any.downcast_ref::<E>() {
handler(event, meta)
} else {
EventResponse::Ignored
}
});
let entry = HandlerEntry {
id,
handler: boxed,
options,
type_id,
};
if let Ok(mut handlers) = self.handlers.write() {
let type_handlers = handlers.entry(type_id).or_default();
type_handlers.push(entry);
type_handlers.sort_by(|a, b| b.options.priority.cmp(&a.options.priority));
}
id
}
pub fn once<E: CustomEvent>(
&mut self,
handler: impl Fn(&E, &mut EventMeta) -> EventResponse + Send + Sync + 'static,
) -> CustomHandlerId {
self.on_with_options::<E>(handler, HandlerOptions::default().once(true))
}
pub fn off(&mut self, handler_id: CustomHandlerId) {
if let Ok(mut handlers) = self.handlers.write() {
for type_handlers in handlers.values_mut() {
type_handlers.retain(|h| h.id != handler_id);
}
handlers.retain(|_, list| !list.is_empty());
}
}
pub fn off_all<E: CustomEvent>(&mut self) {
let type_id = TypeId::of::<E>();
if let Ok(mut handlers) = self.handlers.write() {
handlers.remove(&type_id);
}
}
pub fn clear(&mut self) {
if let Ok(mut handlers) = self.handlers.write() {
handlers.clear();
}
}
pub fn dispatch<E: CustomEvent>(&self, event: E) -> DispatchResult {
self.dispatch_envelope(EventEnvelope::new(event))
}
pub fn dispatch_envelope<E: CustomEvent>(&self, envelope: EventEnvelope<E>) -> DispatchResult {
let EventEnvelope { event, mut meta } = envelope;
let type_id = TypeId::of::<E>();
let mut handlers_to_remove = Vec::new();
let mut handler_count = 0;
let handlers = match self.handlers.read() {
Ok(h) => h,
Err(_) => return DispatchResult::error("Failed to acquire lock"),
};
let type_handlers = match handlers.get(&type_id) {
Some(h) => h,
None => {
return DispatchResult {
event_id: meta.id,
cancelled: false,
propagation_stopped: false,
handler_count: 0,
error: None,
};
}
};
for entry in type_handlers.iter().filter(|h| h.options.capture) {
meta.phase = DispatchPhase::Capture;
let response = (entry.handler)(&event, &mut meta);
handler_count += 1;
if entry.options.once {
handlers_to_remove.push(entry.id);
}
if response.should_cancel() {
meta.cancel();
}
if response.should_stop() {
meta.stop_propagation();
}
if meta.is_propagation_stopped() || meta.is_immediate_propagation_stopped() {
break;
}
}
if !meta.is_propagation_stopped() {
for entry in type_handlers.iter().filter(|h| !h.options.capture) {
meta.phase = DispatchPhase::Target;
let response = (entry.handler)(&event, &mut meta);
handler_count += 1;
if entry.options.once {
handlers_to_remove.push(entry.id);
}
if response.should_cancel() {
meta.cancel();
}
if response.should_stop() {
meta.stop_propagation();
}
if meta.is_propagation_stopped() || meta.is_immediate_propagation_stopped() {
break;
}
}
}
drop(handlers);
if !handlers_to_remove.is_empty() {
if let Ok(mut pending) = self.pending_removals.write() {
pending.extend(handlers_to_remove);
}
}
self.cleanup_handlers();
DispatchResult {
event_id: meta.id,
cancelled: meta.is_cancelled(),
propagation_stopped: meta.is_propagation_stopped(),
handler_count,
error: None,
}
}
pub fn has_handlers<E: CustomEvent>(&self) -> bool {
let type_id = TypeId::of::<E>();
self.handlers
.read()
.map(|h| h.get(&type_id).is_some_and(|list| !list.is_empty()))
.unwrap_or(false)
}
pub fn handler_count<E: CustomEvent>(&self) -> usize {
let type_id = TypeId::of::<E>();
self.handlers
.read()
.map(|h| h.get(&type_id).map_or(0, |list| list.len()))
.unwrap_or(0)
}
fn cleanup_handlers(&self) {
let pending = {
let mut pending = match self.pending_removals.write() {
Ok(p) => p,
Err(_) => return,
};
std::mem::take(&mut *pending)
};
if !pending.is_empty() {
if let Ok(mut handlers) = self.handlers.write() {
for type_handlers in handlers.values_mut() {
type_handlers.retain(|h| !pending.contains(&h.id));
}
handlers.retain(|_, list| !list.is_empty());
}
}
}
}
impl Default for EventDispatcher {
fn default() -> Self {
Self::new()
}
}
impl Clone for EventDispatcher {
fn clone(&self) -> Self {
Self {
handlers: Arc::clone(&self.handlers),
pending_removals: Arc::clone(&self.pending_removals),
}
}
}