titanium_rs/
framework.rs

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    /// Set a global error handler for commands.
50    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    /// Dispatch a command.
60    pub async fn dispatch(&self, name: &str, ctx: Context) {
61        if let Some(handler) = self.commands.get(name) {
62            // We need to clone context for error handler if needed,
63            // but Context is cheap to clone (Arc internal).
64            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                    // Default error logging
71                    eprintln!("Command execution failed: {:?}", err);
72                }
73            }
74        }
75    }
76}