feagi_data_structures/
feagi_signal.rs

1use std::collections::HashMap;
2use std::fmt::Debug;
3use crate::{define_index, FeagiDataError};
4
5define_index!(FeagiSignalIndex, u32, "A unique identifier for a subscription to a FeagiSignal");
6
7pub struct FeagiSignal<T> { // Totally not stolen concept from Godot
8    listeners: HashMap<FeagiSignalIndex, Box<dyn Fn(&T) + Send + Sync>>,
9    next_index: u32,
10}
11
12
13impl<T> FeagiSignal<T> {
14    pub fn new() -> Self {
15        Self { listeners: HashMap::new(), next_index: 0 }
16    }
17
18    pub fn connect<F>(&mut self, f: F) -> FeagiSignalIndex // Will overflow after 4 billion subscriptions. Too bad!
19    where
20        F: Fn(&T) + Send + Sync + 'static,
21    {
22        self.listeners.insert(self.next_index.into(), Box::new(f));
23        self.next_index += 1;
24        (self.next_index - 1).into()
25    }
26
27    pub fn disconnect(&mut self, index: FeagiSignalIndex) -> Result<(), FeagiDataError> {
28        if self.listeners.remove(&index).is_some() {
29            return Ok(())
30        }
31        Err(FeagiDataError::BadParameters(format!("No subscription found with identifier {}!", index)))
32    }
33
34    pub fn emit(&self, value: T) {
35        for f in &self.listeners {
36            f.1(&value);
37        }
38    }
39}
40
41impl<T> Debug for FeagiSignal<T> {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        f.debug_struct("FeagiSignal")
44            .field("listener_count", &self.listeners.len())
45            .field("next_index", &self.next_index)
46            .field("listener_indices", &self.listeners.keys().collect::<Vec<_>>())
47            .finish()
48    }
49}