use std::error::Error;
use std::sync::Arc;
pub trait Input {
fn name(&self) -> String {
std::any::type_name::<Self>().to_string()
}
fn description(&self) -> String {
format!("Input of type {}", self.name())
}
type Output;
}
#[async_trait::async_trait]
pub trait InputHandler<T: Input + Send + Sync> {
async fn handle(&self, input: Arc<T>) -> Result<T::Output, Box<dyn Error>>;
}
#[async_trait::async_trait]
pub trait Mediator<I: Input + Send + Sync + 'static> {
fn get_input_handler(&self) -> Arc<dyn InputHandler<I> + Send + Sync>;
async fn send(&self, input: I) -> Result<I::Output, Box<dyn Error>> {
let input = Arc::new(input);
let handler = self.get_input_handler();
handler.handle(input).await
}
}
#[macro_export]
macro_rules! handlers {
($($item:tt)*) => {
$crate::__handlers_internal!($($item)*);
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __handlers_internal {
() => {};
($tinput:path: $thandler:ty, $($rest:tt)*) => {
const _: () = {
use $crate::inject::Injectable;
use $crate::mediator::{InputHandler, Mediator};
use $crate::resolver::Resolver;
use std::sync::Arc;
impl Mediator<$tinput> for () {
fn get_input_handler(&self) -> Arc<dyn InputHandler<$tinput> + Send + Sync> {
let handler = <$thandler as Injectable>::inject();
Arc::new(handler) as Arc<dyn InputHandler<$tinput> + Send + Sync>
}
}
impl Resolver<dyn Mediator<$tinput> + Send + Sync> for () {
fn resolve(&self) -> Arc<dyn Mediator<$tinput> + Send + Sync + 'static> {
Arc::new(())
}
}
};
$crate::__handlers_internal!($($rest)*);
};
($tinput:path: $thandler:ty) => {
const _: () = {
use $crate::inject::Injectable;
use $crate::mediator::{InputHandler, Mediator};
use $crate::resolver::Resolver;
use std::sync::Arc;
impl Mediator<$tinput> for () {
fn get_input_handler(&self) -> Arc<dyn InputHandler<$tinput> + Send + Sync> {
let handler = <$thandler as Injectable>::inject();
Arc::new(handler) as Arc<dyn InputHandler<$tinput> + Send + Sync>
}
}
impl Resolver<dyn Mediator<$tinput> + Send + Sync> for () {
fn resolve(&self) -> Arc<dyn Mediator<$tinput> + Send + Sync + 'static> {
Arc::new(())
}
}
};
};
}
pub async fn send<I: Input + Send + Sync + 'static>(
input: I,
) -> Result<I::Output, Box<dyn std::error::Error>>
where
(): Mediator<I>,
{
<() as Mediator<I>>::send(&(), input).await
}
#[cfg(test)]
mod test {
#[test]
fn mediator_test() {
use crate::mediator::{Input, InputHandler, send};
use async_trait::async_trait;
use futures::executor::block_on;
use std::error::Error;
use std::sync::Arc;
struct TestInput {
pub value: u32,
}
impl Input for TestInput {
type Output = u32;
}
struct TestInputHandler;
#[async_trait]
impl InputHandler<TestInput> for TestInputHandler {
async fn handle(
&self,
input: Arc<TestInput>,
) -> Result<<TestInput as Input>::Output, Box<dyn Error>> {
Ok(input.value + 1)
}
}
impl crate::inject::Injectable for TestInputHandler {
fn inject() -> Self {
TestInputHandler
}
}
crate::handlers!(TestInput: TestInputHandler); let output = block_on(send(TestInput { value: 41 })).unwrap(); assert!(output == 42); }
}