use std::convert::Infallible;
use std::marker::PhantomData;
use std::sync::Arc;
use typeway_core::effects::{AllProvided, ECons, ENil, Effect};
use typeway_core::ApiSpec;
use crate::body::BoxBody;
use crate::router::{Router, RouterService};
use crate::serves::Serves;
pub struct MNil;
pub struct MCons<A, Tail>(PhantomData<(A, Tail)>);
pub struct MHere;
pub struct MThere<T>(PhantomData<T>);
pub trait HasMount<A, Idx> {}
impl<A, Tail> HasMount<A, MHere> for MCons<A, Tail> {}
impl<A, Head, Tail, Idx> HasMount<A, MThere<Idx>> for MCons<Head, Tail> where Tail: HasMount<A, Idx> {}
#[diagnostic::on_unimplemented(
message = "not all sub-APIs have been mounted for `{Self}`",
label = "some sub-APIs are missing — add more .mount() calls",
note = "each sub-API in the API type must have a corresponding .mount() call"
)]
pub trait AllMounted<M, Idx> {}
impl<M> AllMounted<M, ()> for () {}
macro_rules! impl_all_mounted_for_tuple {
($($T:ident, $I:ident);+) => {
impl<Mounted, $($T: ApiSpec, $I,)+> AllMounted<Mounted, ($($I,)+)> for ($($T,)+)
where $(Mounted: HasMount<$T, $I>,)+ {}
};
}
impl_all_mounted_for_tuple!(A, IA);
impl_all_mounted_for_tuple!(A, IA; B, IB);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID; E, IE);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID; E, IE; F, IF);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID; E, IE; F, IF; G, IG);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID; E, IE; F, IF; G, IG; H, IH);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID; E, IE; F, IF; G, IG; H, IH; I, II);
impl_all_mounted_for_tuple!(A, IA; B, IB; C, IC; D, ID; E, IE; F, IF; G, IG; H, IH; I, II; J, IJ);
pub struct ServerBuilder<A: ApiSpec, Mounted = MNil, Provided = ENil> {
router: Router,
_api: PhantomData<A>,
_mounted: PhantomData<Mounted>,
_provided: PhantomData<Provided>,
}
impl<A: ApiSpec> ServerBuilder<A, MNil, ENil> {
pub fn new() -> Self {
ServerBuilder {
router: Router::new(),
_api: PhantomData,
_mounted: PhantomData,
_provided: PhantomData,
}
}
}
impl<A: ApiSpec, M, P> ServerBuilder<A, M, P> {
pub fn mount<Sub: ApiSpec, H: Serves<Sub>>(
mut self,
handlers: H,
) -> ServerBuilder<A, MCons<Sub, M>, P> {
handlers.register(&mut self.router);
ServerBuilder {
router: self.router,
_api: PhantomData,
_mounted: PhantomData,
_provided: PhantomData,
}
}
pub fn provide<E: Effect>(self) -> ServerBuilder<A, M, ECons<E, P>> {
ServerBuilder {
router: self.router,
_api: PhantomData,
_mounted: PhantomData,
_provided: PhantomData,
}
}
pub fn layer<L>(self, layer: L) -> LayeredServerBuilder<A, M, P, L::Service>
where
L: tower_layer::Layer<RouterService>,
L::Service: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
<L::Service as tower_service::Service<http::Request<hyper::body::Incoming>>>::Future:
Send + 'static,
{
let router = Arc::new(self.router);
let svc = RouterService::new(router.clone());
let layered = layer.layer(svc);
LayeredServerBuilder {
service: layered,
router,
_api: PhantomData,
_mounted: PhantomData,
_provided: PhantomData,
}
}
pub fn with_state<T: Clone + Send + Sync + 'static>(self, state: T) -> Self {
self.router.set_state_injector(Arc::new(move |ext| {
ext.insert(state.clone());
}));
self
}
pub fn max_body_size(self, max: usize) -> Self {
self.router.set_max_body_size(max);
self
}
pub fn build<MIdx, PIdx>(self) -> crate::server::Server<A>
where
A: AllMounted<M, MIdx>,
A: AllProvided<P, PIdx>,
{
crate::server::Server::from_router(Arc::new(self.router))
}
}
pub struct LayeredServerBuilder<A: ApiSpec, Mounted, Provided, S> {
service: S,
router: Arc<Router>,
_api: PhantomData<A>,
_mounted: PhantomData<Mounted>,
_provided: PhantomData<Provided>,
}
impl<A: ApiSpec, M, P, S> LayeredServerBuilder<A, M, P, S> {
pub fn provide<E: Effect>(self) -> LayeredServerBuilder<A, M, ECons<E, P>, S> {
LayeredServerBuilder {
service: self.service,
router: self.router,
_api: PhantomData,
_mounted: PhantomData,
_provided: PhantomData,
}
}
}
impl<A: ApiSpec, M, P, S> LayeredServerBuilder<A, M, P, S>
where
S: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
S::Future: Send + 'static,
{
pub fn build<MIdx, PIdx>(self) -> crate::server::LayeredServer<S>
where
A: AllMounted<M, MIdx>,
A: AllProvided<P, PIdx>,
{
crate::server::LayeredServer {
service: self.service,
router: self.router,
}
}
pub fn layer<L>(self, layer: L) -> LayeredServerBuilder<A, M, P, L::Service>
where
L: tower_layer::Layer<S>,
L::Service: tower_service::Service<
http::Request<hyper::body::Incoming>,
Response = http::Response<BoxBody>,
Error = Infallible,
> + Clone
+ Send
+ 'static,
<L::Service as tower_service::Service<http::Request<hyper::body::Incoming>>>::Future:
Send + 'static,
{
LayeredServerBuilder {
service: layer.layer(self.service),
router: self.router,
_api: PhantomData,
_mounted: PhantomData,
_provided: PhantomData,
}
}
}
impl<A: ApiSpec> Default for ServerBuilder<A, MNil, ENil> {
fn default() -> Self {
Self::new()
}
}