use parking_lot::Mutex;
use std::collections::HashMap;
use std::sync::{Arc, Weak};
use uuid::Uuid;
struct EventHandlersList<V: Clone + 'static> {
index: usize,
#[allow(clippy::type_complexity)]
callbacks: HashMap<usize, Arc<Box<dyn Fn(V) + Send + Sync>>>,
}
impl<V: Clone + 'static> Default for EventHandlersList<V> {
fn default() -> Self {
Self {
index: 0,
callbacks: HashMap::new(),
}
}
}
#[derive(Clone)]
pub(super) struct EventHandlers<V: Clone + 'static> {
handlers: Arc<Mutex<HashMap<SubscriptionTarget, EventHandlersList<V>>>>,
}
impl<V: Clone + 'static> EventHandlers<V> {
pub(super) fn new() -> Self {
let handlers = Arc::<Mutex<HashMap<SubscriptionTarget, EventHandlersList<V>>>>::default();
Self { handlers }
}
pub(super) fn add(
&self,
target_id: SubscriptionTarget,
callback: Box<dyn Fn(V) + Send + Sync + 'static>,
) -> SubscriptionHandler {
let index;
{
let mut event_handlers = self.handlers.lock();
let list = event_handlers
.entry(target_id)
.or_insert_with(EventHandlersList::default);
index = list.index;
list.index += 1;
list.callbacks.insert(index, Arc::new(Box::new(callback)));
drop(event_handlers);
}
SubscriptionHandler::new({
let event_handlers_weak = Arc::downgrade(&self.handlers);
Box::new(move || {
if let Some(event_handlers) = event_handlers_weak.upgrade() {
let removed_handler;
{
let mut handlers = event_handlers.lock();
let is_empty = {
let list = handlers.get_mut(&target_id).unwrap();
removed_handler = list.callbacks.remove(&index);
list.callbacks.is_empty()
};
if is_empty {
handlers.remove(&target_id);
}
}
drop(removed_handler);
}
})
})
}
pub(super) fn call_callbacks_with_value(&self, target_id: &SubscriptionTarget, value: V) {
let handlers = self.handlers.lock();
if let Some(list) = handlers.get(target_id) {
if list.callbacks.len() == 1 {
let callback = list.callbacks.values().next().cloned().unwrap();
drop(handlers);
callback(value);
} else {
let callbacks = list.callbacks.values().cloned().collect::<Vec<_>>();
drop(handlers);
for callback in callbacks {
callback(value.clone());
}
}
}
}
pub(super) fn downgrade(&self) -> WeakEventHandlers<V> {
WeakEventHandlers {
handlers: Arc::downgrade(&self.handlers),
}
}
}
#[derive(Clone)]
pub(super) struct WeakEventHandlers<V: Clone + 'static> {
handlers: Weak<Mutex<HashMap<SubscriptionTarget, EventHandlersList<V>>>>,
}
impl<V: Clone + 'static> WeakEventHandlers<V> {
pub(super) fn upgrade(&self) -> Option<EventHandlers<V>> {
self.handlers
.upgrade()
.map(|handlers| EventHandlers { handlers })
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub(crate) enum SubscriptionTarget {
Uuid(Uuid),
Number(u32),
}
impl From<u32> for SubscriptionTarget {
fn from(number: u32) -> Self {
Self::Number(number)
}
}
pub(crate) struct SubscriptionHandler {
remove_callback: Option<Box<dyn FnOnce() + Send + Sync>>,
}
impl SubscriptionHandler {
fn new(remove_callback: Box<dyn FnOnce() + Send + Sync>) -> Self {
Self {
remove_callback: Some(remove_callback),
}
}
}
impl Drop for SubscriptionHandler {
fn drop(&mut self) {
let remove_callback = self.remove_callback.take().unwrap();
remove_callback();
}
}