studiole_command/macros/
server_macro.rs1use crate::prelude::*;
2
3#[macro_export]
4macro_rules! define_commands_server {
5 ($($kind:ident($req:ty, $handler:ty)),* $(,)?) => {
6 #[derive(Clone)]
7 pub enum CommandHandler {
8 $(
9 $kind(Arc<$handler>),
10 )*
11 }
12
13 impl IHandler for CommandHandler {}
14
15 pub enum Command {
16 $(
17 $kind($req, Arc<$handler>),
18 )*
19 }
20
21 #[async_trait]
22 impl ICommand<CommandHandler, CommandSuccess, CommandFailure> for Command {
23 fn new<T: Executable + Send + Sync + 'static>(
24 request: T,
25 handler: CommandHandler,
26 ) -> Self {
27 let request_any: Box<dyn Any> = Box::new(request);
28 match handler {
29 $(
30 CommandHandler::$kind(handler) => {
31 let request = request_any
32 .downcast::<$req>()
33 .expect("Request type should match handler");
34 Self::$kind(*request, handler)
35 },
36 )*
37 }
38 }
39
40 async fn execute(self) -> Result<CommandSuccess, CommandFailure> {
41 match self {
42 $(
43 Self::$kind(request, handler) => {
44 match handler.execute(&request).await {
45 Ok(result) => Ok(CommandSuccess::$kind(result)),
46 Err(e) => Err(CommandFailure::$kind(e)),
47 }
48 },
49 )*
50 }
51 }
52 }
53
54 impl Display for Command {
55 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
56 let name = match &self {
57 $(
58 Self::$kind(request, _) => request.to_string(),
59 )*
60 };
61 f.write_str(&name)
62 }
63 }
64
65 $(
66 impl From<Arc<$handler>> for CommandHandler {
67 fn from(handler: Arc<$handler>) -> Self {
68 Self::$kind(handler)
69 }
70 }
71 )*
72
73 pub trait WithCommands: Sized {
74 fn with_commands(self) -> impl Future<Output = Result<Self, Report<ServiceError>>> + Send;
75 }
76
77 impl WithCommands for ServiceProvider {
78 async fn with_commands(self) -> Result<Self, Report<ServiceError>> {
79 let mut registry: CommandRegistry<CommandInfo> = CommandRegistry::new();
80 $(
81 let handler = self.get_service::<$handler>().await?;
82 registry.register::<$req, $handler>(handler);
83 )*
84 Ok(self.with_instance(registry))
85 }
86 }
87 };
88}
89
90pub trait IHandler: Clone + Send + Sync {}
92
93#[async_trait]
95pub trait ICommand<H: IHandler, S: ISuccess, F: IFailure>: Display + Send + Sync {
96 fn new<T: Executable + Send + Sync + 'static>(request: T, handler: H) -> Self;
98 async fn execute(self) -> Result<S, F>;
100}