use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
use crate::{define_index, FeagiDataError};
define_index!(FeagiSignalIndex, u32, "A unique identifier for a subscription to a FeagiSignal");
pub struct FeagiSignal<T> {
listeners: HashMap<FeagiSignalIndex, Box<dyn FnMut(&T) + Send>>,
next_index: u32,
}
impl<T> FeagiSignal<T> {
pub fn new() -> Self {
Self { listeners: HashMap::new(), next_index: 0 }
}
pub fn connect<F>(&mut self, f: F) -> FeagiSignalIndex where
F: FnMut(&T) + Send + 'static,
{
self.listeners.insert(self.next_index.into(), Box::new(f));
self.next_index += 1;
(self.next_index - 1).into()
}
pub fn disconnect(&mut self, index: FeagiSignalIndex) -> Result<(), FeagiDataError> {
if self.listeners.remove(&index).is_some() {
return Ok(())
}
Err(FeagiDataError::BadParameters(format!("No subscription found with identifier {}!", index)))
}
pub fn emit(&mut self, value: &T) {
for f in self.listeners.values_mut() {
f(value);
}
}
pub fn connect_with_shared_state<S, F>(&mut self, state: Arc<Mutex<S>>, mut callback: F) -> FeagiSignalIndex
where
S: Send + 'static,
F: FnMut(&mut S, &T) + Send + 'static,
{
self.connect(move |event| {
if let Ok(mut guard) = state.lock() {
callback(&mut *guard, event);
}
})
}
pub fn listener_count(&self) -> usize {
self.listeners.len()
}
pub fn disconnect_all(&mut self) {
self.listeners.clear();
}
}
impl<T> Default for FeagiSignal<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> Debug for FeagiSignal<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FeagiSignal")
.field("listener_count", &self.listeners.len())
.field("next_index", &self.next_index)
.field("listener_indices", &self.listeners.keys().collect::<Vec<_>>())
.finish()
}
}