use crate::AppError;
use crate::extractor::from_request::FromRequest;
use crate::handler::{FnOnceTuple, Req, TypedHandler, handler_to_svc};
use crate::http::response::into_response::IntoResponse;
use crate::router::HttpSvc;
use bytes::Bytes;
use http_body::Body;
use http_body_util::BodyExt;
use hyper::Response;
use miko_core::{BoxError, MikoError};
use std::future::Future;
use std::sync::Arc;
use tower::{Layer, Service, ServiceExt, util::BoxCloneService};
pub trait LayerExt<Svc>: Sized {
fn layer<L, B>(self, layer: L) -> HttpSvc<Req>
where
Svc: Service<Req>,
L: Layer<Svc>,
L::Service: Service<Req, Response = Response<B>> + Clone + Send + 'static,
<L::Service as Service<Req>>::Error: Into<AppError>,
B: Body<Data = Bytes> + Send + Sync + 'static,
B::Error: Into<BoxError>,
<L::Service as Service<Req>>::Future: Send + 'static;
fn with_layer<L, B>(self, layer: L) -> HttpSvc<Req>
where
Svc: Service<Req>,
L: Layer<Svc>,
L::Service: Service<Req, Response = Response<B>> + Clone + Send + 'static,
<L::Service as Service<Req>>::Error: Into<AppError>,
B: Body<Data = Bytes> + Send + Sync + 'static,
B::Error: Into<BoxError>,
<L::Service as Service<Req>>::Future: Send + 'static,
{
self.layer(layer)
}
}
pub trait WithState<S>: Sized {
fn with_state<A, Fut, R, M>(self, state: S) -> HttpSvc<Req>
where
Self: FnOnceTuple<A, Output = Fut> + Clone + Send + Sync + 'static,
A: FromRequest<S, M> + Send + 'static,
Fut: Future<Output = R> + Send + 'static,
R: IntoResponse,
M: Send + Sync + 'static;
}
impl LayerExt<HttpSvc<Req>> for HttpSvc<Req> {
fn layer<L, B>(self, layer: L) -> HttpSvc<Req>
where
L: Layer<Self>,
L::Service: Service<Req, Response = Response<B>> + Clone + Send + 'static,
<L::Service as Service<Req>>::Error: Into<AppError>,
B: Body<Data = Bytes> + Send + Sync + 'static,
B::Error: Into<BoxError>,
<L::Service as Service<Req>>::Future: Send + 'static,
{
let layered_svc = layer
.layer(self)
.map_response(|resp| {
let (parts, body) = resp.into_parts();
let body = body.map_err(|e| MikoError::from(e.into())).boxed_unsync();
Response::from_parts(parts, body)
})
.map_err(Into::into);
BoxCloneService::new(layered_svc)
}
}
impl<F, S> WithState<S> for F
where
S: Send + Sync + 'static,
{
fn with_state<A, Fut, R, M>(self, state: S) -> HttpSvc<Req>
where
F: FnOnceTuple<A, Output = Fut> + Clone + Send + Sync + 'static,
A: FromRequest<S, M> + Send + 'static,
Fut: Future<Output = R> + Send + 'static,
R: IntoResponse,
M: Send + Sync + 'static,
{
let handler_arc = Arc::new(TypedHandler::new(self, Arc::new(state)));
handler_to_svc(handler_arc)
}
}