1use ahash::AHashMap;
2use std::future::Future;
3use std::pin::Pin;
4
5use crate::context::Context;
6
7use crate::error::TitaniumError;
8
9type CommandHandler = Box<
10 dyn Fn(Context) -> Pin<Box<dyn Future<Output = Result<(), TitaniumError>> + Send>>
11 + Send
12 + Sync,
13>;
14type ErrorHandler =
15 Box<dyn Fn(TitaniumError, Context) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
16
17pub struct Framework {
18 pub commands: AHashMap<String, CommandHandler>,
19 pub on_error: Option<ErrorHandler>,
20}
21
22impl Default for Framework {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl Framework {
29 #[must_use]
30 pub fn new() -> Self {
31 Self {
32 commands: AHashMap::new(),
33 on_error: None,
34 }
35 }
36
37 pub fn command<F, Fut>(mut self, name: &str, handler: F) -> Self
38 where
39 F: Fn(Context) -> Fut + Send + Sync + 'static,
40 Fut: Future<Output = Result<(), TitaniumError>> + Send + 'static,
41 {
42 self.commands.insert(
43 name.to_string(),
44 Box::new(move |ctx| Box::pin(handler(ctx))),
45 );
46 self
47 }
48
49 pub fn on_error<F, Fut>(mut self, handler: F) -> Self
51 where
52 F: Fn(TitaniumError, Context) -> Fut + Send + Sync + 'static,
53 Fut: Future<Output = ()> + Send + 'static,
54 {
55 self.on_error = Some(Box::new(move |err, ctx| Box::pin(handler(err, ctx))));
56 self
57 }
58
59 pub async fn dispatch(&self, name: &str, ctx: Context) {
61 if let Some(handler) = self.commands.get(name) {
62 let ctx_clone = ctx.clone();
65
66 if let Err(err) = handler(ctx).await {
67 if let Some(error_handler) = &self.on_error {
68 error_handler(err, ctx_clone).await;
69 } else {
70 eprintln!("Command execution failed: {:?}", err);
72 }
73 }
74 }
75 }
76}