Skip to main content

a3s_boot/routing/
handler.rs

1use crate::{BootError, BootRequest, BootResponse, BoxFuture, ModuleRef, Result};
2use std::future::Future;
3
4/// Type-erased route handler used by adapters.
5pub trait RouteHandler: Send + Sync + 'static {
6    fn call(&self, request: BootRequest) -> BoxFuture<'static, Result<BootResponse>>;
7}
8
9impl<F, Fut> RouteHandler for F
10where
11    F: Fn(BootRequest) -> Fut + Send + Sync + 'static,
12    Fut: Future<Output = Result<BootResponse>> + Send + 'static,
13{
14    fn call(&self, request: BootRequest) -> BoxFuture<'static, Result<BootResponse>> {
15        Box::pin(self(request))
16    }
17}
18
19pub(crate) struct RequestScopedRouteHandler<F> {
20    factory: F,
21}
22
23impl<F> RequestScopedRouteHandler<F> {
24    pub(crate) fn new(factory: F) -> Self {
25        Self { factory }
26    }
27}
28
29impl<F, H> RouteHandler for RequestScopedRouteHandler<F>
30where
31    F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
32    H: RouteHandler,
33{
34    fn call(&self, request: BootRequest) -> BoxFuture<'static, Result<BootResponse>> {
35        let Some(module_ref) = request.module_ref().cloned() else {
36            return Box::pin(async {
37                Err(BootError::Internal(
38                    "request-scoped route requires a module context".to_string(),
39                ))
40            });
41        };
42
43        match (self.factory)(&module_ref) {
44            Ok(handler) => handler.call(request),
45            Err(error) => Box::pin(async move { Err(error) }),
46        }
47    }
48}