composable_tower_http/extract/
or.rs

1use super::extractor::Extractor;
2
3#[derive(Debug, Clone)]
4pub struct OrExtractor<L, R> {
5    left: L,
6    right: R,
7}
8
9impl<L, R> OrExtractor<L, R> {
10    pub const fn new(left: L, right: R) -> Self {
11        Self { left, right }
12    }
13}
14
15#[derive(Debug, Clone)]
16pub enum Or<L, R> {
17    Left(L),
18    Right(R),
19}
20
21impl<L, R> Extractor for OrExtractor<L, R>
22where
23    L: Extractor + Send + Sync,
24    R: Extractor + Send + Sync,
25    L::Error: Send,
26{
27    type Extracted = Or<L::Extracted, R::Extracted>;
28
29    type Error = OrError<L::Error, R::Error>;
30
31    async fn extract(&self, headers: &http::HeaderMap) -> Result<Self::Extracted, Self::Error> {
32        match self.left.extract(headers).await {
33            Ok(extracted) => Ok(Or::Left(extracted)),
34            Err(left_error) => match self.right.extract(headers).await {
35                Ok(extracted) => Ok(Or::Right(extracted)),
36                Err(right_error) => Err(OrError {
37                    left: left_error,
38                    right: right_error,
39                }),
40            },
41        }
42    }
43}
44
45#[derive(Debug, thiserror::Error)]
46#[error("Left: {left}, Right: {right}")]
47pub struct OrError<L, R> {
48    pub left: L,
49    pub right: R,
50}
51
52#[cfg(feature = "axum")]
53mod axum {
54    use axum::response::{IntoResponse, Response};
55
56    use super::OrError;
57
58    impl<L, R> IntoResponse for OrError<L, R>
59    where
60        L: IntoResponse,
61    {
62        fn into_response(self) -> Response {
63            self.left.into_response()
64        }
65    }
66
67    impl<L, R> From<OrError<L, R>> for Response
68    where
69        L: IntoResponse,
70    {
71        fn from(value: OrError<L, R>) -> Self {
72            value.into_response()
73        }
74    }
75}