a3s-boot 0.1.1

Adapter-first modular Rust web framework for A3S inspired by Nest.js
Documentation
use super::{
    catch_errors, ExceptionFilter, ExecutionInterceptor, ExecutionInterceptorAdapter, Guard,
    Interceptor, Middleware, Pipe,
};
use crate::BootErrorKind;
use std::any::TypeId;
use std::collections::HashMap;
use std::sync::Arc;

pub(crate) struct PipelineComponent<T: ?Sized> {
    type_id: TypeId,
    inner: Arc<T>,
}

impl<T: ?Sized> Clone for PipelineComponent<T> {
    fn clone(&self) -> Self {
        Self {
            type_id: self.type_id,
            inner: Arc::clone(&self.inner),
        }
    }
}

impl<T: ?Sized> PipelineComponent<T> {
    pub(crate) fn inner(&self) -> &T {
        self.inner.as_ref()
    }

    fn type_id(&self) -> TypeId {
        self.type_id
    }
}

impl PipelineComponent<dyn Pipe> {
    pub(crate) fn new<P>(pipe: P) -> Self
    where
        P: Pipe,
    {
        Self {
            type_id: TypeId::of::<P>(),
            inner: Arc::new(pipe),
        }
    }

    fn replacement<T, P>(pipe: P) -> Self
    where
        T: Pipe,
        P: Pipe,
    {
        Self {
            type_id: TypeId::of::<T>(),
            inner: Arc::new(pipe),
        }
    }
}

impl PipelineComponent<dyn Guard> {
    pub(crate) fn new<G>(guard: G) -> Self
    where
        G: Guard,
    {
        Self {
            type_id: TypeId::of::<G>(),
            inner: Arc::new(guard),
        }
    }

    pub(crate) fn from_arc(guard: Arc<dyn Guard>) -> Self {
        Self {
            type_id: TypeId::of::<Arc<dyn Guard>>(),
            inner: guard,
        }
    }

    fn replacement<T, G>(guard: G) -> Self
    where
        T: Guard,
        G: Guard,
    {
        Self {
            type_id: TypeId::of::<T>(),
            inner: Arc::new(guard),
        }
    }
}

impl PipelineComponent<dyn Interceptor> {
    pub(crate) fn new<I>(interceptor: I) -> Self
    where
        I: Interceptor,
    {
        Self {
            type_id: TypeId::of::<I>(),
            inner: Arc::new(interceptor),
        }
    }

    fn replacement<T, I>(interceptor: I) -> Self
    where
        T: Interceptor,
        I: Interceptor,
    {
        Self {
            type_id: TypeId::of::<T>(),
            inner: Arc::new(interceptor),
        }
    }
}

impl PipelineComponent<dyn ExceptionFilter> {
    pub(crate) fn new<F>(filter: F) -> Self
    where
        F: ExceptionFilter,
    {
        Self {
            type_id: TypeId::of::<F>(),
            inner: Arc::new(filter),
        }
    }

    fn replacement<T, F>(filter: F) -> Self
    where
        T: ExceptionFilter,
        F: ExceptionFilter,
    {
        Self {
            type_id: TypeId::of::<T>(),
            inner: Arc::new(filter),
        }
    }
}

#[derive(Clone, Default)]
pub(crate) struct PipelineComponents {
    pub middleware: Vec<Arc<dyn Middleware>>,
    pub pipes: Vec<PipelineComponent<dyn Pipe>>,
    pub guards: Vec<PipelineComponent<dyn Guard>>,
    pub interceptors: Vec<PipelineComponent<dyn Interceptor>>,
    pub filters: Vec<PipelineComponent<dyn ExceptionFilter>>,
    pub validation_enabled: bool,
}

impl PipelineComponents {
    pub fn push_middleware<M>(&mut self, middleware: M)
    where
        M: Middleware,
    {
        self.middleware.push(Arc::new(middleware));
    }

    pub fn push_middleware_arc(&mut self, middleware: Arc<dyn Middleware>) {
        self.middleware.push(middleware);
    }

    pub fn push_pipe<P>(&mut self, pipe: P)
    where
        P: Pipe,
    {
        self.pipes.push(PipelineComponent::<dyn Pipe>::new(pipe));
    }

    pub fn push_guard<G>(&mut self, guard: G)
    where
        G: Guard,
    {
        self.guards.push(PipelineComponent::<dyn Guard>::new(guard));
    }

    pub fn push_guard_arc(&mut self, guard: Arc<dyn Guard>) {
        self.guards
            .push(PipelineComponent::<dyn Guard>::from_arc(guard));
    }

    pub fn push_interceptor<I>(&mut self, interceptor: I)
    where
        I: Interceptor,
    {
        self.interceptors
            .push(PipelineComponent::<dyn Interceptor>::new(interceptor));
    }

    pub fn push_execution_interceptor<I>(&mut self, interceptor: I)
    where
        I: ExecutionInterceptor,
    {
        self.push_interceptor(ExecutionInterceptorAdapter::new(interceptor));
    }

    pub fn push_execution_interceptor_arc(&mut self, interceptor: Arc<dyn ExecutionInterceptor>) {
        self.push_interceptor(ExecutionInterceptorAdapter::new(interceptor));
    }

    pub fn push_filter<F>(&mut self, filter: F)
    where
        F: ExceptionFilter,
    {
        self.filters
            .push(PipelineComponent::<dyn ExceptionFilter>::new(filter));
    }

    pub fn push_catch_filter<I, F>(&mut self, kinds: I, filter: F)
    where
        I: IntoIterator<Item = BootErrorKind>,
        F: ExceptionFilter,
    {
        self.push_filter(catch_errors(kinds, filter));
    }

    pub fn enable_validation(&mut self) {
        self.validation_enabled = true;
    }
}

#[derive(Default)]
pub(crate) struct PipelineOverrides {
    pipes: HashMap<TypeId, PipelineComponent<dyn Pipe>>,
    guards: HashMap<TypeId, PipelineComponent<dyn Guard>>,
    interceptors: HashMap<TypeId, PipelineComponent<dyn Interceptor>>,
    filters: HashMap<TypeId, PipelineComponent<dyn ExceptionFilter>>,
}

impl PipelineOverrides {
    pub(crate) fn is_empty(&self) -> bool {
        self.pipes.is_empty()
            && self.guards.is_empty()
            && self.interceptors.is_empty()
            && self.filters.is_empty()
    }

    pub(crate) fn override_pipe<T, P>(&mut self, pipe: P)
    where
        T: Pipe,
        P: Pipe,
    {
        self.pipes.insert(
            TypeId::of::<T>(),
            PipelineComponent::<dyn Pipe>::replacement::<T, P>(pipe),
        );
    }

    pub(crate) fn override_guard<T, G>(&mut self, guard: G)
    where
        T: Guard,
        G: Guard,
    {
        self.guards.insert(
            TypeId::of::<T>(),
            PipelineComponent::<dyn Guard>::replacement::<T, G>(guard),
        );
    }

    pub(crate) fn override_interceptor<T, I>(&mut self, interceptor: I)
    where
        T: Interceptor,
        I: Interceptor,
    {
        self.interceptors.insert(
            TypeId::of::<T>(),
            PipelineComponent::<dyn Interceptor>::replacement::<T, I>(interceptor),
        );
    }

    pub(crate) fn override_filter<T, F>(&mut self, filter: F)
    where
        T: ExceptionFilter,
        F: ExceptionFilter,
    {
        self.filters.insert(
            TypeId::of::<T>(),
            PipelineComponent::<dyn ExceptionFilter>::replacement::<T, F>(filter),
        );
    }

    pub(crate) fn apply_to_pipes(&self, pipes: &mut [PipelineComponent<dyn Pipe>]) {
        apply(&self.pipes, pipes);
    }

    pub(crate) fn apply_to_guards(&self, guards: &mut [PipelineComponent<dyn Guard>]) {
        apply(&self.guards, guards);
    }

    pub(crate) fn apply_to_interceptors(
        &self,
        interceptors: &mut [PipelineComponent<dyn Interceptor>],
    ) {
        apply(&self.interceptors, interceptors);
    }

    pub(crate) fn apply_to_filters(&self, filters: &mut [PipelineComponent<dyn ExceptionFilter>]) {
        apply(&self.filters, filters);
    }
}

fn apply<T: ?Sized>(
    overrides: &HashMap<TypeId, PipelineComponent<T>>,
    components: &mut [PipelineComponent<T>],
) {
    for component in components {
        if let Some(replacement) = overrides.get(&component.type_id()) {
            *component = replacement.clone();
        }
    }
}