composable-tower-http 0.3.1

Highly customizable http utilities built on top of tower.
Documentation
use super::extractor::Extractor;

#[derive(Debug, Clone)]
pub struct OrExtractor<L, R> {
    left: L,
    right: R,
}

impl<L, R> OrExtractor<L, R> {
    pub const fn new(left: L, right: R) -> Self {
        Self { left, right }
    }
}

#[derive(Debug, Clone)]
pub enum Or<L, R> {
    Left(L),
    Right(R),
}

impl<L, R> Extractor for OrExtractor<L, R>
where
    L: Extractor + Send + Sync,
    R: Extractor + Send + Sync,
    L::Error: Send,
{
    type Extracted = Or<L::Extracted, R::Extracted>;

    type Error = OrError<L::Error, R::Error>;

    async fn extract(&self, headers: &http::HeaderMap) -> Result<Self::Extracted, Self::Error> {
        match self.left.extract(headers).await {
            Ok(extracted) => Ok(Or::Left(extracted)),
            Err(left_error) => match self.right.extract(headers).await {
                Ok(extracted) => Ok(Or::Right(extracted)),
                Err(right_error) => Err(OrError {
                    left: left_error,
                    right: right_error,
                }),
            },
        }
    }
}

#[derive(Debug, thiserror::Error)]
#[error("Left: {left}, Right: {right}")]
pub struct OrError<L, R> {
    pub left: L,
    pub right: R,
}

#[cfg(feature = "axum")]
mod axum {
    use axum::response::{IntoResponse, Response};

    use super::OrError;

    impl<L, R> IntoResponse for OrError<L, R>
    where
        L: IntoResponse,
    {
        fn into_response(self) -> Response {
            self.left.into_response()
        }
    }

    impl<L, R> From<OrError<L, R>> for Response
    where
        L: IntoResponse,
    {
        fn from(value: OrError<L, R>) -> Self {
            value.into_response()
        }
    }
}