use crate::core::*;
pub use noema_macros::input;
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>) -> NoemaResult<T::Output>;
}
#[async_trait::async_trait]
pub trait Sender<I: Input + Send + Sync + 'static> {
fn get_input_handler() -> arc_dyn!(InputHandler<I>);
async fn send(input: I) -> NoemaResult<I::Output> {
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::core::*;
use $crate::sender::{InputHandler, Sender};
impl Sender<$tinput> for Container {
fn get_input_handler() -> arc_dyn!(InputHandler<$tinput>) {
let handler = <$thandler>::inject(&Container);
Arc::new(handler) as Arc<dyn InputHandler<$tinput> + Send + Sync>
}
}
};
$crate::__handlers_internal!($($rest)*);
};
($tinput:path: $thandler:ty) => {
const _: () = {
use $crate::core::*;
use $crate::sender::{InputHandler, Sender};
impl Sender<$tinput> for Container {
fn get_input_handler() -> arc_dyn!(InputHandler<$tinput>) {
let handler = <$thandler>::inject(&Container);
Arc::new(handler) as Arc<dyn InputHandler<$tinput> + Send + Sync>
}
}
};
};
}
pub async fn send<I: Input + Send + Sync + 'static>(input: I) -> Result<I::Output, BoxDynError>
where
Container: Sender<I>,
{
<Container as Sender<I>>::send(input).await
}
#[cfg(test)]
mod test {
use crate::core::*;
#[test]
fn mediator_test() {
use crate::sender::{Input, InputHandler, input, send};
use async_trait::async_trait;
use futures::executor::block_on;
struct Increaser {}
impl Increaser {
fn add(&self, value: u32) -> u32 {
value + 1
}
}
#[input(u32)]
struct TestInput {
pub value: u32,
}
#[derive(Injectable)]
struct TestInputHandler {
increaser: Arc<Increaser>,
}
#[async_trait]
impl InputHandler<TestInput> for TestInputHandler {
async fn handle(
&self,
input: Arc<TestInput>,
) -> NoemaResult<<TestInput as Input>::Output> {
Ok(self.increaser.add(input.value))
}
}
crate::handlers!(TestInput: TestInputHandler); impl Resolver<Increaser> for Container {
fn resolve() -> Arc<Increaser> {
Arc::new(Increaser {})
}
}
let output = block_on(send(TestInput { value: 41 })).unwrap(); assert!(output == 42); }
}