use crate::http::endpoints::handlers::RouteHandler;
use crate::{HttpResult, status};
#[cfg(feature = "middleware")]
use crate::middleware::{HttpContext, MiddlewareFn, Middlewares, NextFn, from_handler};
#[cfg(not(feature = "middleware"))]
use crate::http::request::HttpRequest;
#[derive(Clone)]
pub(crate) enum Layer {
Handler(RouteHandler),
#[cfg(feature = "middleware")]
Middleware(MiddlewareFn),
}
impl From<RouteHandler> for Layer {
#[inline]
fn from(handler: RouteHandler) -> Self {
Self::Handler(handler)
}
}
#[cfg(feature = "middleware")]
impl From<MiddlewareFn> for Layer {
#[inline]
fn from(mw: MiddlewareFn) -> Self {
Self::Middleware(mw)
}
}
impl From<Layer> for RouteHandler {
#[inline]
fn from(layer: Layer) -> Self {
match layer {
Layer::Handler(handler) => handler,
#[cfg(feature = "middleware")]
Layer::Middleware(_) => unreachable!(),
}
}
}
#[cfg(feature = "middleware")]
impl From<Layer> for MiddlewareFn {
#[inline]
fn from(layer: Layer) -> Self {
match layer {
Layer::Middleware(mw) => mw,
Layer::Handler(handler) => from_handler(handler),
}
}
}
#[derive(Clone)]
pub(crate) enum RoutePipeline {
#[cfg(feature = "middleware")]
Builder(Middlewares),
#[cfg(feature = "middleware")]
Middleware(Option<NextFn>),
#[cfg(not(feature = "middleware"))]
Handler(Option<RouteHandler>),
}
impl From<Layer> for RoutePipeline {
fn from(handler: Layer) -> Self {
#[cfg(feature = "middleware")]
let pipeline = Self::Builder(Middlewares::from(MiddlewareFn::from(handler)));
#[cfg(not(feature = "middleware"))]
let pipeline = Self::Handler(Some(RouteHandler::from(handler)));
pipeline
}
}
impl RoutePipeline {
pub(super) fn new() -> Self {
#[cfg(feature = "middleware")]
let pipeline = Self::Builder(Middlewares::new());
#[cfg(not(feature = "middleware"))]
let pipeline = Self::Handler(None);
pipeline
}
pub(super) fn insert(&mut self, layer: Layer) {
match self {
#[cfg(feature = "middleware")]
Self::Builder(mx) => mx.add(layer.into()),
#[cfg(feature = "middleware")]
Self::Middleware(_) => (),
#[cfg(not(feature = "middleware"))]
Self::Handler(route_handler) => *route_handler = Some(layer.into()),
}
}
#[cfg(feature = "middleware")]
pub(crate) async fn call(self, ctx: HttpContext) -> HttpResult {
match self {
Self::Middleware(Some(next)) => {
let next = next.clone();
next(ctx).await
}
_ => status!(405),
}
}
#[cfg(not(feature = "middleware"))]
pub(crate) async fn call(self, req: HttpRequest) -> HttpResult {
match self {
Self::Handler(Some(handler)) => handler.call(req).await,
_ => status!(405),
}
}
#[cfg(feature = "middleware")]
pub(super) fn compose(&mut self) {
let next = match self {
Self::Middleware(_) => return,
Self::Builder(mx) => {
mx.pipeline.rotate_left(1);
mx.compose()
}
};
*self = Self::Middleware(next)
}
}
#[cfg(all(test, not(feature = "middleware")))]
mod tests {
use super::{Layer, RoutePipeline};
use crate::http::endpoints::handlers::{Handler, RouteHandler};
use crate::{HttpRequest, HttpResult, status};
use futures_util::future::BoxFuture;
use std::sync::Arc;
struct NoopHandler;
impl Handler for NoopHandler {
fn call(&self, _req: HttpRequest) -> BoxFuture<'_, HttpResult> {
Box::pin(async { status!(204) })
}
}
#[test]
fn pipeline_from_layer_contains_handler() {
let handler: RouteHandler = Arc::new(NoopHandler);
let pipeline = RoutePipeline::from(Layer::from(handler.clone()));
match pipeline {
RoutePipeline::Handler(Some(inner)) => {
assert!(Arc::ptr_eq(&inner, &handler));
}
_ => panic!("expected handler pipeline"),
}
}
#[test]
fn insert_sets_handler_in_pipeline() {
let handler: RouteHandler = Arc::new(NoopHandler);
let mut pipeline = RoutePipeline::new();
pipeline.insert(Layer::from(handler.clone()));
match pipeline {
RoutePipeline::Handler(Some(inner)) => {
assert!(Arc::ptr_eq(&inner, &handler));
}
_ => panic!("expected handler pipeline"),
}
}
}