use crate::prelude::*;
#[macro_export]
macro_rules! define_commands_server {
($($kind:ident($req:ty, $handler:ty)),* $(,)?) => {
#[derive(Clone)]
pub enum CommandHandler {
$(
$kind(Arc<$handler>),
)*
}
impl IHandler for CommandHandler {}
pub enum Command {
$(
$kind($req, Arc<$handler>),
)*
}
#[async_trait]
impl ICommand<CommandHandler, CommandSuccess, CommandFailure> for Command {
fn new<T: Executable + Send + Sync + 'static>(
request: T,
handler: CommandHandler,
) -> Self {
let request_any: Box<dyn Any> = Box::new(request);
match handler {
$(
CommandHandler::$kind(handler) => {
let request = request_any
.downcast::<$req>()
.expect("Request type should match handler");
Self::$kind(*request, handler)
},
)*
}
}
async fn execute(self) -> Result<CommandSuccess, CommandFailure> {
match self {
$(
Self::$kind(request, handler) => {
match handler.execute(&request).await {
Ok(result) => Ok(CommandSuccess::$kind(result)),
Err(e) => Err(CommandFailure::$kind(e)),
}
},
)*
}
}
}
impl Display for Command {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let name = match &self {
$(
Self::$kind(request, _) => request.to_string(),
)*
};
f.write_str(&name)
}
}
$(
impl From<Arc<$handler>> for CommandHandler {
fn from(handler: Arc<$handler>) -> Self {
Self::$kind(handler)
}
}
)*
impl RegisterHandlers for CommandInfo {
async fn register_handlers(
services: &ServiceProvider,
) -> Result<CommandRegistry<Self>, Report<ResolveError>> {
let mut registry = CommandRegistry::new();
$(
let handler = services.get_async::<$handler>().await?;
registry.register::<$req, $handler>(handler);
)*
Ok(registry)
}
}
pub trait WithCommands: Sized {
fn with_commands(self) -> Self;
}
impl WithCommands for ServiceBuilder {
fn with_commands(self) -> Self {
self
$(
.with_type_async::<$handler>()
)*
.with_type_async::<CommandRegistry<CommandInfo>>()
.with_type_async::<CommandRunner<CommandInfo>>()
.with_type::<CommandMediator<CommandInfo>>()
.with_type::<WorkerPool<CommandInfo>>()
.with_type::<CommandEvents<CommandInfo>>()
.with_type::<ProgressWriterFactory>()
.with_type::<CliProgress<CommandInfo>>()
}
}
};
}
pub trait IHandler: Clone + Send + Sync {}
#[async_trait]
pub trait ICommand<H: IHandler, S: ISuccess, F: IFailure>: Display + Send + Sync {
fn new<T: Executable + Send + Sync + 'static>(request: T, handler: H) -> Self;
async fn execute(self) -> Result<S, F>;
}