actix-state-guards 0.1.0

This crate provides a more flexible guard function for the [`actix-web`] framework
Documentation
use crate::Guard as GuardTrait;

use std::marker::PhantomData;
use std::rc::Rc;
use std::{future::Future, pin::Pin};

use actix_web::body::MessageBody;
use actix_web::dev::{forward_ready, Service as ServiceTrait, ServiceRequest, ServiceResponse};
use actix_web::{Error as ActixWebError, FromRequest, ResponseError};

pub struct StateGuardMiddleware<Service, Guard, Args, Error> {
    service: Rc<Service>,
    guard: Rc<Guard>,
    args_marker: PhantomData<Args>,
    error_marker: PhantomData<Error>,
}

impl<Service, Guard, Args, Error> StateGuardMiddleware<Service, Guard, Args, Error> {
    pub(crate) fn new(
        guard: Rc<Guard>,
        service: Service,
    ) -> StateGuardMiddleware<Service, Guard, Args, Error> {
        Self {
            guard,
            service: Rc::new(service),
            args_marker: PhantomData,
            error_marker: PhantomData,
        }
    }
}

impl<Service, Body, Guard, Args, Error> ServiceTrait<ServiceRequest>
    for StateGuardMiddleware<Service, Guard, Args, Error>
where
    Service: ServiceTrait<ServiceRequest, Response = ServiceResponse<Body>, Error = ActixWebError>
        + 'static,
    Body: MessageBody,
    Guard: GuardTrait<Args, Error>,
    Error: ResponseError + 'static,
    Args: FromRequest,
{
    type Response = Service::Response;

    type Error = Service::Error;

    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    forward_ready!(service);

    fn call(&self, mut req: ServiceRequest) -> Self::Future {
        let service = Rc::clone(&self.service);
        let guard = Rc::clone(&self.guard);

        Box::pin(async move {
            match guard.call_guard_with_service_request(&mut req).await {
                Ok(()) => service.call(req).await,
                Err(err) => Err(err.into()),
            }
        })
    }
}