a3s_boot/pipeline/
filter.rs1use super::ExecutionContext;
2use crate::{BootError, BootErrorKind, BootResponse, BoxFuture, Result};
3
4pub 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
27pub 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
70pub 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}