1use std::{
2 collections::HashMap,
3 fmt::{self, Debug},
4 marker::PhantomData,
5 sync::Arc,
6};
7
8use async_fn_traits::{AsyncFn1, AsyncFn2, AsyncFn3, AsyncFn4};
9use async_trait::async_trait;
10
11use crate::{
12 Error,
13 commands::{Context, Converter, checks::Check},
14};
15
16#[derive(Clone)]
17pub struct Command<
18 E: From<Error> + Clone + Debug + Send + Sync + 'static,
19 S: Debug + Clone + Send + Sync + 'static,
20> {
21 pub name: String,
22 pub handle: Arc<dyn CommandHandle<(), E, S>>,
23 pub error: Option<Arc<dyn CommandErrorHandler<E, S>>>,
24 pub children: HashMap<String, Command<E, S>>,
25 pub checks: Vec<Arc<dyn Check<E, S>>>,
26 pub aliases: Vec<String>,
27 pub description: Option<String>,
28 pub signature: Option<String>,
29 pub parents: Vec<String>,
30 pub hidden: bool,
31}
32
33impl<
34 E: From<Error> + Clone + Debug + Send + Sync + 'static,
35 S: Debug + Clone + Send + Sync + 'static,
36> fmt::Debug for Command<E, S> {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 f.debug_struct("Command")
39 .field("name", &self.name)
40 .field("description", &self.description)
41 .field("children", &self.children)
42 .field("aliases", &self.aliases)
43 .field("signature", &self.signature)
44 .finish_non_exhaustive()
45 }
46}
47
48impl<
49 E: From<Error> + Clone + Debug + Send + Sync + 'static,
50 S: Debug + Clone + Send + Sync + 'static,
51> Command<E, S>
52{
53 pub fn new<T: Send + Sync + 'static, I: Into<String>, F: CommandHandle<T, E, S> + Clone>(
54 name: I,
55 handle: F,
56 ) -> Self {
57 let erased = ErasedCommandHandler {
58 handle,
59 _p: PhantomData,
60 };
61
62 Self {
63 name: name.into(),
64 handle: Arc::new(erased),
65 error: None,
66 children: HashMap::new(),
67 checks: Vec::new(),
68 aliases: Vec::new(),
69 description: None,
70 signature: None,
71 parents: Vec::new(),
72 hidden: false,
73 }
74 }
75
76 pub fn child(mut self, mut command: Self) -> Self {
77 command.parents = self.parents.clone();
78 command.parents.push(self.name.clone());
79
80 self.children.insert(command.name.clone(), command.clone());
81
82 for alias in command.aliases.clone() {
83 self.children.insert(alias, command.clone());
84 }
85
86 self
87 }
88
89 pub fn error<H: CommandErrorHandler<E, S> + 'static>(mut self, handler: H) -> Self {
90 self.error = Some(Arc::new(handler));
91
92 self
93 }
94
95 pub fn description<I: Into<String>>(mut self, description: I) -> Self {
96 self.description = Some(description.into());
97
98 self
99 }
100
101 pub fn signature<I: Into<String>>(mut self, signature: I) -> Self {
102 self.signature = Some(signature.into());
103
104 self
105 }
106
107 pub fn check<C: Check<E, S>>(mut self, check: C) -> Self {
108 self.checks.push(Arc::new(check));
109
110 self
111 }
112
113 pub fn alias<I: Into<String>>(mut self, alias: I) -> Self {
114 self.aliases.push(alias.into());
115
116 self
117 }
118
119 pub fn hidden(mut self) -> Self {
120 self.hidden = true;
121
122 self
123 }
124
125 pub fn children(&self) -> Vec<Command<E, S>> {
126 self.children
127 .clone()
128 .into_iter()
129 .filter(|(name, command)| name == &command.name)
130 .map(|(_, command)| command)
131 .collect()
132 }
133
134 pub fn get_command(&self, name: &str) -> Option<Command<E, S>> {
135 self.children.get(name).cloned()
136 }
137
138 pub async fn can_run(&self, context: Context<E, S>) -> Result<bool, E> {
139 for check in &self.checks {
140 if check.run(context.clone()).await? == false {
141 return Err(Error::CheckFailure.into());
142 }
143 }
144
145 Ok(true)
146 }
147
148 pub async fn invoke(&self, context: Context<E, S>) -> Result<(), E> {
149 (self.handle).handle(context).await
150 }
151}
152
153#[async_trait]
154pub trait CommandHandle<
155 T,
156 E: From<Error> + Clone + Debug + Send + Sync + 'static,
157 S: Debug + Clone + Send + Sync + 'static,
158>: Send + Sync + 'static
159{
160 async fn handle(&self, context: Context<E, S>) -> Result<(), E>;
161}
162
163#[async_trait]
164impl<E, S, F> CommandHandle<(), E, S> for F
165where
166 E: From<Error> + Clone + Debug + Send + Sync + 'static,
167 S: Debug + Clone + Send + Sync + 'static,
168 F: AsyncFn1<Context<E, S>, Output = Result<(), E>> + Send + Sync + 'static,
169 F::OutputFuture: Send,
170{
171 async fn handle(&self, context: Context<E, S>) -> Result<(), E> {
172 (self)(context).await
173 }
174}
175
176#[async_trait]
177impl<T1, E, S, F> CommandHandle<(T1,), E, S> for F
178where
179 T1: Converter<E, S> + Send,
180 E: From<Error> + Clone + Debug + Send + Sync + 'static,
181 S: Debug + Clone + Send + Sync + 'static,
182 F: AsyncFn2<Context<E, S>, T1, Output = Result<(), E>> + Send + Sync + 'static,
183 F::OutputFuture: Send,
184{
185 async fn handle(&self, context: Context<E, S>) -> Result<(), E> {
186 let t1 = T1::from_context(&context).await?;
187 (self)(context, t1).await
188 }
189}
190
191#[async_trait]
192impl<T1, T2, E, S, F> CommandHandle<(T1, T2), E, S> for F
193where
194 T1: Converter<E, S> + Send,
195 T2: Converter<E, S> + Send,
196 E: From<Error> + Clone + Debug + Send + Sync + 'static,
197 S: Debug + Clone + Send + Sync + 'static,
198 F: AsyncFn3<Context<E, S>, T1, T2, Output = Result<(), E>> + Send + Sync + 'static,
199 F::OutputFuture: Send,
200{
201 async fn handle(&self, context: Context<E, S>) -> Result<(), E> {
202 let t1 = T1::from_context(&context).await?;
203 let t2 = T2::from_context(&context).await?;
204
205 (self)(context, t1, t2).await
206 }
207}
208
209#[async_trait]
210impl<T1, T2, T3, E, S, F> CommandHandle<(T1, T2, T3), E, S> for F
211where
212 T1: Converter<E, S> + Send,
213 T2: Converter<E, S> + Send,
214 T3: Converter<E, S> + Send,
215 E: From<Error> + Clone + Debug + Send + Sync + 'static,
216 S: Debug + Clone + Send + Sync + 'static,
217 F: AsyncFn4<Context<E, S>, T1, T2, T3, Output = Result<(), E>> + Send + Sync + 'static,
218 F::OutputFuture: Send,
219{
220 async fn handle(&self, context: Context<E, S>) -> Result<(), E> {
221 let t1 = T1::from_context(&context).await?;
222 let t2 = T2::from_context(&context).await?;
223 let t3 = T3::from_context(&context).await?;
224
225 (self)(context, t1, t2, t3).await
226 }
227}
228
229struct ErasedCommandHandler<
230 T: Send + Sync + 'static,
231 E: From<Error> + Clone + Debug + Send + Sync + 'static,
232 S: Debug + Clone + Send + Sync + 'static,
233 H: CommandHandle<T, E, S>,
234> {
235 handle: H,
236 _p: PhantomData<(T, E, S)>,
237}
238
239#[async_trait]
240impl<
241 T: Send + Sync + 'static,
242 E: From<Error> + Clone + Debug + Send + Sync + 'static,
243 S: Debug + Clone + Send + Sync + 'static,
244 H: CommandHandle<T, E, S>,
245> CommandHandle<(), E, S> for ErasedCommandHandler<T, E, S, H>
246{
247 async fn handle(&self, context: Context<E, S>) -> Result<(), E> {
248 self.handle.handle(context).await
249 }
250}
251
252#[async_trait]
253pub trait CommandErrorHandler<
254 E: From<Error> + Clone + Debug + Send + Sync + 'static,
255 S: Debug + Clone + Send + Sync + 'static,
256>: Send + Sync {
257 async fn handle(&self, context: Context<E, S>, error: E) -> Result<(), E>;
258}
259
260#[async_trait]
261impl<E, S, F> CommandErrorHandler<E, S> for F where
262 E: From<Error> + Clone + Debug + Send + Sync + 'static,
263 S: Debug + Clone + Send + Sync + 'static,
264 F: AsyncFn2<Context<E, S>, E, Output = Result<(), E>> + Send + Sync + 'static,
265 F::OutputFuture: Send
266{
267 async fn handle(&self, context: Context<E, S>, error: E) -> Result<(), E> {
268 (self)(context, error).await
269 }
270}