Skip to main content

a3s_boot/pipeline/
filter.rs

1use super::ExecutionContext;
2use crate::{BootError, BootErrorKind, BootResponse, BoxFuture, Result};
3
4/// Maps route/pipeline errors to HTTP responses.
5pub trait ExceptionFilter: Send + Sync + 'static {
6    fn catch(
7        &self,
8        context: ExecutionContext,
9        error: BootError,
10    ) -> BoxFuture<'static, Result<Option<BootResponse>>>;
11}
12
13impl<F, Fut> ExceptionFilter for F
14where
15    F: Fn(ExecutionContext, BootError) -> Fut + Send + Sync + 'static,
16    Fut: std::future::Future<Output = Result<Option<BootResponse>>> + Send + 'static,
17{
18    fn catch(
19        &self,
20        context: ExecutionContext,
21        error: BootError,
22    ) -> BoxFuture<'static, Result<Option<BootResponse>>> {
23        Box::pin(self(context, error))
24    }
25}
26
27/// Exception filter wrapper that only handles selected [`BootErrorKind`] values.
28pub struct CatchFilter<F> {
29    kinds: Vec<BootErrorKind>,
30    filter: F,
31}
32
33impl<F> CatchFilter<F> {
34    pub fn new<I>(kinds: I, filter: F) -> Self
35    where
36        I: IntoIterator<Item = BootErrorKind>,
37    {
38        Self {
39            kinds: kinds.into_iter().collect(),
40            filter,
41        }
42    }
43
44    pub fn kinds(&self) -> &[BootErrorKind] {
45        &self.kinds
46    }
47
48    pub fn into_inner(self) -> F {
49        self.filter
50    }
51}
52
53impl<F> ExceptionFilter for CatchFilter<F>
54where
55    F: ExceptionFilter,
56{
57    fn catch(
58        &self,
59        context: ExecutionContext,
60        error: BootError,
61    ) -> BoxFuture<'static, Result<Option<BootResponse>>> {
62        if self.kinds.is_empty() || self.kinds.contains(&error.kind()) {
63            return self.filter.catch(context, error);
64        }
65
66        Box::pin(async { Ok(None) })
67    }
68}
69
70/// Build a Nest-style catch filter for selected [`BootErrorKind`] values.
71pub fn catch_errors<I, F>(kinds: I, filter: F) -> CatchFilter<F>
72where
73    I: IntoIterator<Item = BootErrorKind>,
74    F: ExceptionFilter,
75{
76    CatchFilter::new(kinds, filter)
77}