use std::collections::HashMap;
use std::sync::Arc;
use crate::{IoHandler, IoResult, IoType};
use evorule_tcb::JsonValue;
#[derive(Clone)]
pub struct IoDispatcher {
handlers: HashMap<IoType, Arc<dyn IoHandler>>,
}
impl IoDispatcher {
pub fn new() -> Self {
Self {
handlers: HashMap::new(),
}
}
pub fn register(&mut self, io_type: IoType, handler: Arc<dyn IoHandler>) {
self.handlers.insert(io_type, handler);
}
pub fn builder() -> IoDispatcherBuilder {
IoDispatcherBuilder::new()
}
pub async fn dispatch(&self, io_type: &IoType, params: &JsonValue) -> IoResult {
match self.handlers.get(io_type) {
Some(handler) => handler.execute(params).await,
None => {
tracing::warn!(
"Unknown IoType: {}, no handler registered",
io_type.as_str()
);
Err(format!(
"no handler registered for IoType: {}",
io_type.as_str()
))
}
}
}
pub fn contains(&self, io_type: &IoType) -> bool {
self.handlers.contains_key(io_type)
}
pub fn known_types(&self) -> impl Iterator<Item = &IoType> {
self.handlers.keys()
}
}
impl Default for IoDispatcher {
fn default() -> Self {
Self::new()
}
}
pub struct IoDispatcherBuilder {
handlers: HashMap<IoType, Arc<dyn IoHandler>>,
}
impl IoDispatcherBuilder {
pub fn new() -> Self {
Self {
handlers: HashMap::new(),
}
}
pub fn register(mut self, io_type: IoType, handler: Arc<dyn IoHandler>) -> Self {
self.handlers.insert(io_type, handler);
self
}
pub fn build(self) -> IoDispatcher {
IoDispatcher {
handlers: self.handlers,
}
}
}
impl Default for IoDispatcherBuilder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct EchoHandler;
#[async_trait::async_trait]
impl IoHandler for EchoHandler {
async fn execute(&self, params: &JsonValue) -> IoResult {
Ok(params.clone())
}
}
#[test]
fn dispatcher_routes_by_io_type() {
let mut d = IoDispatcher::new();
d.register(IoType::new("retrieve"), Arc::new(EchoHandler));
assert!(d.contains(&IoType::new("retrieve")));
assert!(!d.contains(&IoType::new("file")));
assert_eq!(d.known_types().count(), 1);
}
#[tokio::test]
async fn dispatch_hit_and_miss() {
let d = IoDispatcher::builder()
.register(IoType::new("retrieve"), Arc::new(EchoHandler))
.build();
let params = JsonValue::Null;
assert!(d.dispatch(&IoType::new("retrieve"), ¶ms).await.is_ok());
assert!(d.dispatch(&IoType::new("file"), ¶ms).await.is_err());
}
#[test]
fn new_equals_factory_key_collision() {
let mut d = IoDispatcher::new();
d.register(IoType::call_service(), Arc::new(EchoHandler));
assert!(d.contains(&IoType::new("call_service")));
}
}