use crate::{define_index, FeagiDataError};
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::{Arc, Mutex};
define_index!(
FeagiSignalIndex,
u32,
"A unique identifier for a subscription to a FeagiSignal"
);
type SignalListener<T> = Box<dyn FnMut(&T) + Send>;
pub struct FeagiSignal<T> {
listeners: HashMap<FeagiSignalIndex, SignalListener<T>>,
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()
}
}