Skip to main content

nagisa_core/
handler.rs

1//! Handler 抽象:任意 `async fn(A0..An) -> HandlerResult`(每个 `Ai: FromContext`)
2//! 由宏按 arity(参数个数)批量生成 blanket impl,擦除为 `Arc<dyn ErasedHandler>`。
3use crate::ctx::Ctx;
4use crate::extract::{FromContext, Reject};
5use futures::future::BoxFuture;
6use std::future::Future;
7use std::sync::Arc;
8
9/// handler 业务返回:`Ok(())` 处理成功,`Err(e)` 处理出错。
10pub type HandlerResult = nagisa_types::error::Result<()>;
11
12/// 把 handler 体的返回值规整成 [`HandlerResult`],免去 handler 末尾的礼节性 `Ok(())`。
13///
14/// 为 `()` 与 [`HandlerResult`] 两种返回类型实现:返回 `()` 的 handler 自动视作成功
15/// (`Ok(())`),返回 `Result<()>` 的 handler 原样传递其 `Err`。两个 impl 不重叠——
16/// blanket `Handler` impl 约束在 `Fut::Output` 这一关联类型上,每个 `async fn` 的输出
17/// 类型唯一,故无歧义。
18///
19/// 设计取舍:相较「为 `T: Into<HandlerResult>` 做泛型」,这里只覆盖恰好两种返回形态,
20/// 更简单且不会把无关类型误当作合法返回。
21pub trait IntoHandlerResult {
22    fn into_handler_result(self) -> HandlerResult;
23}
24
25impl IntoHandlerResult for () {
26    fn into_handler_result(self) -> HandlerResult {
27        Ok(())
28    }
29}
30
31impl IntoHandlerResult for HandlerResult {
32    fn into_handler_result(self) -> HandlerResult {
33        self
34    }
35}
36
37/// dispatch 视角的单次 handler 执行结果。
38pub enum HandlerOutcome {
39    /// 命中并成功处理。
40    Handled,
41    /// 某提取器 `Skip` → 本 handler 不适用,dispatch 继续传播。
42    Skipped,
43    /// 提取出错或业务返回 `Err` → 记日志,dispatch 继续传播。
44    Errored(nagisa_types::error::Error),
45}
46
47/// 类型擦除的 handler:dispatch 只面向它。
48pub trait ErasedHandler: Send + Sync {
49    fn call(&self, ctx: Arc<Ctx>) -> BoxFuture<'static, HandlerOutcome>;
50}
51
52/// 类型化 handler。由宏为多元 `async fn` 生成 blanket impl;用户一般不手写。
53pub trait Handler<Args>: Clone + Send + Sync + 'static {
54    fn call(&self, ctx: Arc<Ctx>) -> BoxFuture<'static, HandlerOutcome>;
55
56    /// 擦除为 `Arc<dyn ErasedHandler>` 供注册。
57    fn erased(self) -> Arc<dyn ErasedHandler>
58    where
59        Self: Sized,
60        Args: 'static,
61    {
62        Arc::new(HandlerFn { f: self, _args: std::marker::PhantomData })
63    }
64}
65
66/// `Handler<Args>` → `ErasedHandler` 的适配壳(携带 `Args` 幻型以选中正确的 impl)。
67///
68/// `PhantomData<fn() -> Args>` 自身恒为 `Send + Sync`,故壳的 auto `Send`/`Sync`
69/// 只取决于 `F`——无需 `unsafe impl`(本 crate `#![forbid(unsafe_code)]`)。
70struct HandlerFn<F, Args> {
71    f: F,
72    _args: std::marker::PhantomData<fn() -> Args>,
73}
74
75impl<F, Args> ErasedHandler for HandlerFn<F, Args>
76where
77    F: Handler<Args>,
78    Args: 'static,
79{
80    fn call(&self, ctx: Arc<Ctx>) -> BoxFuture<'static, HandlerOutcome> {
81        Handler::call(&self.f, ctx)
82    }
83}
84
85/// 顺序提取一个参数:`Skip`→提前返回 `Skipped`,`Error`→提前返回 `Errored`。
86///
87/// dev 模式(`App::debug()` 注入 `DevMode`)下,`Skip` 不再静默:发一条 `[dev]` `WARN`
88/// 点名是哪个提取器拒绝了本 handler,把「为何没触发」从黑盒变成可见诊断。
89macro_rules! extract_or_bail {
90    ($ty:ty, $ctx:expr) => {
91        match <$ty as FromContext>::from_context(&$ctx).await {
92            Ok(v) => v,
93            Err(Reject::Skip) => {
94                if $ctx.is_dev() {
95                    tracing::warn!(
96                        extractor = std::any::type_name::<$ty>(),
97                        "[dev] skip: extractor rejected (Skip) — handler not applicable"
98                    );
99                }
100                return HandlerOutcome::Skipped;
101            }
102            Err(Reject::Error(e)) => return HandlerOutcome::Errored(e),
103        }
104    };
105}
106
107/// 为 `F: Fn(A0..An) -> Fut` 生成 `Handler<(A0..An,)>` blanket impl。
108macro_rules! impl_handler {
109    ($($ty:ident),*) => {
110        #[allow(non_snake_case, unused_variables)]
111        impl<F, Fut, Out, $($ty,)*> Handler<($($ty,)*)> for F
112        where
113            F: Fn($($ty,)*) -> Fut + Clone + Send + Sync + 'static,
114            Fut: Future<Output = Out> + Send + 'static,
115            Out: IntoHandlerResult,
116            $($ty: FromContext + Send + 'static,)*
117        {
118            fn call(&self, ctx: Arc<Ctx>) -> BoxFuture<'static, HandlerOutcome> {
119                let f = self.clone();
120                Box::pin(async move {
121                    $(let $ty = extract_or_bail!($ty, *ctx);)*
122                    // Handler 体可返回 `()`(自动包成 `Ok(())`)或 `HandlerResult`。
123                    match f($($ty,)*).await.into_handler_result() {
124                        Ok(()) => HandlerOutcome::Handled,
125                        Err(e) => HandlerOutcome::Errored(e),
126                    }
127                })
128            }
129        }
130    };
131}
132
133impl_handler!();
134impl_handler!(A0);
135impl_handler!(A0, A1);
136impl_handler!(A0, A1, A2);
137impl_handler!(A0, A1, A2, A3);
138impl_handler!(A0, A1, A2, A3, A4);
139impl_handler!(A0, A1, A2, A3, A4, A5);
140impl_handler!(A0, A1, A2, A3, A4, A5, A6);
141impl_handler!(A0, A1, A2, A3, A4, A5, A6, A7);
142impl_handler!(A0, A1, A2, A3, A4, A5, A6, A7, A8);
143impl_handler!(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9);
144impl_handler!(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
145impl_handler!(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);