Skip to main content

studiole_command/macros/
web_macro.rs

1use crate::prelude::*;
2
3#[macro_export]
4macro_rules! define_commands_web {
5    ($($kind:ident($req:ty)),* $(,)?) => {
6        #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
7        pub enum CommandRequest {
8            $(
9                $kind($req),
10            )*
11        }
12
13        impl IRequest for CommandRequest {}
14
15        $(
16            impl From<$req> for CommandRequest {
17                fn from(request: $req) -> Self {
18                    Self::$kind(request)
19                }
20            }
21        )*
22
23        #[derive(Clone, Debug, Deserialize, Serialize)]
24        pub enum CommandSuccess {
25            $(
26                $kind(<$req as Executable>::Response),
27            )*
28        }
29
30        impl ISuccess for CommandSuccess {}
31
32        #[derive(Debug)]
33        pub enum CommandFailure {
34            $(
35                $kind(<$req as Executable>::ExecutionError),
36            )*
37        }
38
39        impl IFailure for CommandFailure {}
40
41        #[derive(Clone, Debug, Deserialize, Serialize)]
42        pub struct CommandEvent {
43            kind: EventKind,
44            request: CommandRequest,
45            success: Option<CommandSuccess>,
46        }
47
48        impl IEvent<CommandRequest, CommandSuccess> for CommandEvent {
49            fn new(kind: EventKind, request: CommandRequest, success: Option<CommandSuccess>) -> Self {
50                Self { kind, request, success }
51            }
52
53            fn get_kind(&self) -> &EventKind {
54                &self.kind
55            }
56
57            fn get_request(&self) -> &CommandRequest {
58                &self.request
59            }
60
61            fn get_success(&self) -> &Option<CommandSuccess> {
62                &self.success
63            }
64        }
65
66        pub struct CommandInfo;
67
68        impl ICommandInfo for CommandInfo {
69            type Request = CommandRequest;
70            #[cfg(feature = "server")]
71            type Command =  Command;
72            #[cfg(feature = "server")]
73            type Handler = CommandHandler;
74            type Success = CommandSuccess;
75            type Failure = CommandFailure;
76            type Event = CommandEvent;
77        }
78
79        $(
80            #[allow(irrefutable_let_patterns, unreachable_patterns, clippy::infallible_try_from)]
81            impl TryFrom<CommandRequest> for $req {
82                type Error = CommandRequest;
83                fn try_from(value: CommandRequest) -> Result<Self, Self::Error> {
84                    match value {
85                        CommandRequest::$kind(r) => Ok(r),
86                        other => Err(other),
87                    }
88                }
89            }
90
91            #[allow(irrefutable_let_patterns, unreachable_patterns, clippy::infallible_try_from)]
92            impl TryFrom<CommandSuccess> for <$req as Executable>::Response {
93                type Error = CommandSuccess;
94                fn try_from(value: CommandSuccess) -> Result<Self, Self::Error> {
95                    match value {
96                        CommandSuccess::$kind(r) => Ok(r),
97                        other => Err(other),
98                    }
99                }
100            }
101
102            #[allow(irrefutable_let_patterns, unreachable_patterns, clippy::infallible_try_from)]
103            impl TryFrom<CommandFailure> for <$req as Executable>::ExecutionError {
104                type Error = CommandFailure;
105                fn try_from(value: CommandFailure) -> Result<Self, Self::Error> {
106                    match value {
107                        CommandFailure::$kind(e) => Ok(e),
108                        other => Err(other),
109                    }
110                }
111            }
112        )*
113    };
114}
115
116/// Marker trait for serializable command request enums.
117///
118/// - Requests are keyed by their `Hash` in the [`CommandMediator`].
119/// - If duplicate requests should be tracked independently, include a unique identifier.
120pub trait IRequest:
121    Clone + Debug + DeserializeOwned + Eq + Hash + PartialEq + Send + Serialize + Sync
122{
123}
124
125/// Marker trait for serializable command success enums.
126pub trait ISuccess: Clone + Debug + DeserializeOwned + Send + Serialize + Sync {}
127
128/// Marker trait for command failure enums.
129pub trait IFailure: Debug + Send + Sync {}
130
131/// A command lifecycle event carrying the request and optional success data.
132pub trait IEvent<Req: IRequest, S: ISuccess>: Clone + Debug + Send + Sync {
133    /// Create a new event.
134    fn new(kind: EventKind, request: Req, success: Option<S>) -> Self;
135    /// Lifecycle stage of the event.
136    fn get_kind(&self) -> &EventKind;
137    /// Request that triggered the event.
138    fn get_request(&self) -> &Req;
139    /// Success data, if the command succeeded.
140    fn get_success(&self) -> &Option<S>;
141}
142
143/// Associated types that define a complete command system.
144pub trait ICommandInfo {
145    /// Request enum type.
146    type Request: IRequest;
147    /// Command enum type (server only).
148    #[cfg(feature = "server")]
149    type Command: ICommand<Self::Handler, Self::Success, Self::Failure>;
150    /// Handler enum type (server only).
151    #[cfg(feature = "server")]
152    type Handler: IHandler;
153    /// Success enum type.
154    type Success: ISuccess;
155    /// Failure enum type.
156    type Failure: IFailure;
157    /// Event type.
158    type Event: IEvent<Self::Request, Self::Success>;
159}