use std::fmt::Debug;
use indexmap::IndexMap;
use super::{
mstr::{Endpoint, MStr},
typed_handler::{TypedHandler, TypedIntoHandler},
};
#[derive(Debug)]
pub struct EndpointMap<T: 'static> {
handlers: IndexMap<MStr<Endpoint>, TypedHandler<T>>,
}
impl<T: 'static> Default for EndpointMap<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: 'static> EndpointMap<T> {
#[must_use]
pub fn new() -> Self {
Self {
handlers: IndexMap::new(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.handlers.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.handlers.is_empty()
}
#[must_use]
pub fn endpoints(&self) -> Vec<&str> {
self.handlers.keys().map(|e| e.as_str()).collect()
}
#[must_use]
pub fn is_registered(&self, endpoint: MStr<Endpoint>) -> bool {
self.handlers.contains_key(&endpoint)
}
pub fn register(&mut self, endpoint: MStr<Endpoint>, handler: TypedHandler<T>) {
log::debug!(
"Registering endpoint '{endpoint}' with handler ID {}",
handler.id()
);
self.handlers.insert(endpoint, handler);
}
pub fn deregister(&mut self, endpoint: MStr<Endpoint>) {
log::debug!("Deregistering endpoint '{endpoint}'");
self.handlers.shift_remove(&endpoint);
}
#[must_use]
pub fn get(&self, endpoint: MStr<Endpoint>) -> Option<&TypedHandler<T>> {
self.handlers.get(&endpoint)
}
pub fn send(&self, endpoint: MStr<Endpoint>, message: &T) {
if let Some(handler) = self.handlers.get(&endpoint) {
handler.handle(message);
} else {
log::error!("send: no registered endpoint '{endpoint}'");
}
}
#[must_use]
pub fn try_send(&self, endpoint: MStr<Endpoint>, message: &T) -> bool {
if let Some(handler) = self.handlers.get(&endpoint) {
handler.handle(message);
true
} else {
false
}
}
pub fn clear(&mut self) {
self.handlers.clear();
}
}
#[derive(Debug)]
pub struct IntoEndpointMap<T: 'static> {
handlers: IndexMap<MStr<Endpoint>, TypedIntoHandler<T>>,
}
impl<T: 'static> Default for IntoEndpointMap<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: 'static> IntoEndpointMap<T> {
#[must_use]
pub fn new() -> Self {
Self {
handlers: IndexMap::new(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.handlers.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.handlers.is_empty()
}
#[must_use]
pub fn endpoints(&self) -> Vec<&str> {
self.handlers.keys().map(|e| e.as_str()).collect()
}
#[must_use]
pub fn is_registered(&self, endpoint: MStr<Endpoint>) -> bool {
self.handlers.contains_key(&endpoint)
}
pub fn register(&mut self, endpoint: MStr<Endpoint>, handler: TypedIntoHandler<T>) {
log::debug!(
"Registering endpoint '{endpoint}' with handler ID {}",
handler.id()
);
self.handlers.insert(endpoint, handler);
}
pub fn deregister(&mut self, endpoint: MStr<Endpoint>) {
log::debug!("Deregistering endpoint '{endpoint}'");
self.handlers.shift_remove(&endpoint);
}
#[must_use]
pub fn get(&self, endpoint: MStr<Endpoint>) -> Option<&TypedIntoHandler<T>> {
self.handlers.get(&endpoint)
}
pub fn send(&self, endpoint: MStr<Endpoint>, message: T) {
if let Some(handler) = self.handlers.get(&endpoint) {
handler.handle(message);
} else {
log::error!("send: no registered endpoint '{endpoint}'");
}
}
pub fn try_send(&self, endpoint: MStr<Endpoint>, message: T) -> Result<(), T> {
if let Some(handler) = self.handlers.get(&endpoint) {
handler.handle(message);
Ok(())
} else {
Err(message)
}
}
pub fn clear(&mut self) {
self.handlers.clear();
}
}
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};
use rstest::rstest;
use super::*;
#[rstest]
fn test_endpoint_map_register_and_send() {
let mut endpoints = EndpointMap::<String>::new();
let received = Rc::new(RefCell::new(Vec::new()));
let received_clone = received.clone();
let handler = TypedHandler::from(move |msg: &String| {
received_clone.borrow_mut().push(msg.clone());
});
let endpoint: MStr<Endpoint> = "DataEngine.execute".into();
endpoints.register(endpoint, handler);
endpoints.send(endpoint, &"command1".to_string());
endpoints.send(endpoint, &"command2".to_string());
assert_eq!(*received.borrow(), vec!["command1", "command2"]);
}
#[rstest]
fn test_endpoint_map_deregister() {
let mut endpoints = EndpointMap::<i32>::new();
let received = Rc::new(RefCell::new(Vec::new()));
let received_clone = received.clone();
let handler = TypedHandler::from(move |msg: &i32| {
received_clone.borrow_mut().push(*msg);
});
let endpoint: MStr<Endpoint> = "Test.endpoint".into();
endpoints.register(endpoint, handler);
assert!(endpoints.is_registered(endpoint));
endpoints.deregister(endpoint);
assert!(!endpoints.is_registered(endpoint));
endpoints.send(endpoint, &42);
assert!(received.borrow().is_empty());
}
#[rstest]
fn test_endpoint_map_try_send() {
let mut endpoints = EndpointMap::<String>::new();
let received = Rc::new(RefCell::new(Vec::new()));
let received_clone = received.clone();
let handler = TypedHandler::from(move |msg: &String| {
received_clone.borrow_mut().push(msg.clone());
});
let registered: MStr<Endpoint> = "Registered.endpoint".into();
let unregistered: MStr<Endpoint> = "Unregistered.endpoint".into();
endpoints.register(registered, handler);
assert!(endpoints.try_send(registered, &"test".to_string()));
assert!(!endpoints.try_send(unregistered, &"test".to_string()));
assert_eq!(*received.borrow(), vec!["test"]);
}
#[rstest]
fn test_endpoint_map_replace_handler() {
let mut endpoints = EndpointMap::<i32>::new();
let first_received = Rc::new(RefCell::new(false));
let second_received = Rc::new(RefCell::new(false));
let first_clone = first_received.clone();
let handler1 = TypedHandler::from(move |_: &i32| {
*first_clone.borrow_mut() = true;
});
let second_clone = second_received.clone();
let handler2 = TypedHandler::from(move |_: &i32| {
*second_clone.borrow_mut() = true;
});
let endpoint: MStr<Endpoint> = "Test.endpoint".into();
endpoints.register(endpoint, handler1);
endpoints.register(endpoint, handler2);
endpoints.send(endpoint, &1);
assert!(!*first_received.borrow());
assert!(*second_received.borrow());
}
}