use crate::{error::GridEventError, grid_engine::Change};
use std::{
fmt::Debug,
sync::{Arc, Mutex},
};
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct ChangesEventValue {
changes: Vec<Change>,
}
impl ChangesEventValue {
pub fn new(changes: Vec<Change>) -> Self {
Self { changes }
}
pub fn changes(&self) -> &Vec<Change> {
&self.changes
}
}
pub type ChangesEventFn = Box<dyn Fn(&ChangesEventValue) + Send + 'static + Sync>;
pub struct ListenerFunction {
id: String,
function: ChangesEventFn,
}
impl ListenerFunction {
pub fn new(id: impl Into<String>, function: ChangesEventFn) -> Self {
Self {
id: id.into(),
function,
}
}
}
impl Debug for ListenerFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ListenerFunction")
.field("id", &self.id)
.finish()
}
}
#[derive(Debug, Default)]
pub struct GridEvents {
listener_id_counter: Arc<Mutex<usize>>,
changes_listeners: Vec<ListenerFunction>,
}
impl GridEvents {
pub fn add_changes_listener(
&mut self,
function: impl Fn(&ChangesEventValue) + Send + 'static + Sync,
) -> Result<String, GridEventError> {
let id = {
let mut counter = match self.listener_id_counter.lock() {
Ok(counter) => counter,
Err(_) => {
return Err(GridEventError::ListenerIdNotGenerated);
}
};
*counter += 1;
format!("l_{}", counter)
};
let listener = ListenerFunction::new(id.clone(), Box::new(function));
self.changes_listeners.push(listener);
Ok(id)
}
pub fn remove_changes_listener(&mut self, id: &str) -> Option<ChangesEventFn> {
if let Some(pos) = self
.changes_listeners
.iter()
.position(|listener| listener.id == id)
{
let listener = self.changes_listeners.remove(pos);
Some(listener.function)
} else {
None
}
}
pub(crate) fn trigger_changes_event(&mut self, value: &ChangesEventValue) {
for listener in &mut self.changes_listeners {
(listener.function)(value);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::{Arc, Mutex};
#[test]
fn test_add_changes_listener() {
let mut events = GridEvents::default();
let listener_id = events.add_changes_listener(|_| {}).unwrap();
assert_eq!(events.changes_listeners.len(), 1);
assert!(!listener_id.is_empty());
}
#[test]
fn test_remove_changes_listener() {
let mut events = GridEvents::default();
let listener_id = events.add_changes_listener(|_| {}).unwrap();
events.remove_changes_listener(&listener_id);
assert_eq!(events.changes_listeners.len(), 0);
}
#[test]
fn test_multiple_listeners() {
let mut events = GridEvents::default();
let _id1 = events.add_changes_listener(|_| {}).unwrap();
let _id2 = events.add_changes_listener(|_| {}).unwrap();
let _id3 = events.add_changes_listener(|_| {}).unwrap();
assert_eq!(events.changes_listeners.len(), 3);
assert_ne!(_id1, _id2);
assert_ne!(_id2, _id3);
assert_ne!(_id1, _id3);
}
#[test]
fn test_trigger_changes_event() {
let mut events = GridEvents::default();
let counter = Arc::new(Mutex::new(0));
let counter_clone = counter.clone();
events
.add_changes_listener(move |_| {
let mut count = counter_clone.lock().unwrap();
*count += 1;
})
.unwrap();
let changes = ChangesEventValue { changes: vec![] };
events.trigger_changes_event(&changes);
assert_eq!(*counter.lock().unwrap(), 1);
}
#[test]
fn test_trigger_multiple_listeners() {
let mut events = GridEvents::default();
let counter = Arc::new(Mutex::new(0));
for _ in 0..2 {
let counter_clone = counter.clone();
events
.add_changes_listener(move |_| {
let mut count = counter_clone.lock().unwrap();
*count += 1;
})
.unwrap();
}
let changes = ChangesEventValue { changes: vec![] };
events.trigger_changes_event(&changes);
assert_eq!(*counter.lock().unwrap(), 2);
}
#[test]
fn test_listener_receives_changes() {
let mut events = GridEvents::default();
let received_changes = Arc::new(Mutex::new(Vec::new()));
let received_changes_clone = received_changes.clone();
events
.add_changes_listener(move |event| {
let mut changes = received_changes_clone.lock().unwrap();
changes.extend(event.changes.clone());
})
.unwrap();
let node = crate::node::Node::new("test".to_string(), 0, 0, 1, 1);
let change = Change::Add(crate::grid_engine::AddChangeData::new(node));
let event = ChangesEventValue {
changes: vec![change.clone()],
};
events.trigger_changes_event(&event);
let received = received_changes.lock().unwrap();
let received_change = received.first().unwrap();
assert_eq!(received_change, &change);
}
}