use std::{fmt, rc::Rc};
use crate::{BindCtx, Ctx};
use crate::{Service, ServiceFactory, util::BoxFuture};
pub struct BoxService<St, Req, Res, Err> {
inner: Rc<dyn ServiceObj<St, Req, Res = Res, Error = Err>>,
}
pub fn service<S, St, Req, Res, Err>(service: S) -> BoxService<St, Req, Res, Err>
where
S: Service<St, Req, Res = Res, Error = Err> + 'static,
{
BoxService::new(service)
}
impl<St, Req, Res, Err> BoxService<St, Req, Res, Err> {
pub fn new<S>(service: S) -> Self
where
S: Service<St, Req, Res = Res, Error = Err> + 'static,
{
BoxService {
inner: Rc::new(service),
}
}
}
impl<St, Req, Res, Err> Clone for BoxService<St, Req, Res, Err> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<St, Req, Res, Err> fmt::Debug for BoxService<St, Req, Res, Err> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BoxService").finish()
}
}
impl<St, Req, Res, Err> Service<St, Req> for BoxService<St, Req, Res, Err> {
type Res = Res;
type Error = Err;
fn bind(&self, ctx: BindCtx<'_>) {
self.inner.bind(ctx);
}
#[inline]
async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
self.inner.ready(ctx.cast()).await
}
#[inline]
async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Res, Err> {
self.inner.call(req, ctx.cast()).await
}
#[inline]
async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
self.inner.shutdown(ctx.cast()).await;
}
}
trait ServiceObj<St, Req> {
type Res;
type Error;
fn bind(&self, ctx: BindCtx<'_>);
fn ready<'a>(&'a self, ctx: Ctx<'a, (), St>) -> BoxFuture<'a, Result<(), Self::Error>>;
fn call<'a>(
&'a self,
r: Req,
ctx: Ctx<'a, (), St>,
) -> BoxFuture<'a, Result<Self::Res, Self::Error>>
where
Req: 'a;
fn shutdown<'a>(&'a self, ctx: Ctx<'a, (), St>) -> BoxFuture<'a, ()>
where
St: 'a,
Req: 'a;
}
impl<S, St, Req> ServiceObj<St, Req> for S
where
S: Service<St, Req>,
{
type Res = S::Res;
type Error = S::Error;
fn bind(&self, ctx: BindCtx<'_>) {
Service::bind(self, ctx);
}
#[inline]
fn ready<'a>(&'a self, ctx: Ctx<'a, (), St>) -> BoxFuture<'a, Result<(), Self::Error>> {
Box::pin(async move { Service::ready(self, ctx.cast()).await })
}
#[inline]
fn call<'a>(&'a self, req: Req, ctx: Ctx<'a, (), St>) -> BoxFuture<'a, Result<S::Res, S::Error>>
where
Req: 'a,
{
Box::pin(Service::call(self, req, ctx.cast()))
}
#[inline]
fn shutdown<'a>(&'a self, ctx: Ctx<'a, (), St>) -> BoxFuture<'a, ()>
where
St: 'a,
Req: 'a,
{
Box::pin(Service::shutdown(self, ctx.cast()))
}
}
pub struct BoxServiceFactory<St, Req, Res, Err, InitErr> {
inner: Rc<dyn ServiceFactoryObj<St, Req, Res = Res, Error = Err, InitErr = InitErr>>,
}
pub fn factory<Sf, St, Req>(
factory: Sf,
) -> BoxServiceFactory<St, Req, Sf::Res, Sf::Error, Sf::InitError>
where
Sf: ServiceFactory<St, Req> + 'static,
St: 'static,
Req: 'static,
{
BoxServiceFactory::new(factory)
}
impl<St, Req, Res, Err, InitErr> BoxServiceFactory<St, Req, Res, Err, InitErr>
where
St: 'static,
Req: 'static,
{
pub fn new<Sf>(factory: Sf) -> Self
where
Sf: ServiceFactory<St, Req, Res = Res, Error = Err, InitError = InitErr> + 'static,
St: 'static,
Req: 'static,
{
Self {
inner: Rc::new(factory),
}
}
}
impl<St, Req, Res, Err, InitErr> ServiceFactory<St, Req>
for BoxServiceFactory<St, Req, Res, Err, InitErr>
where
Req: 'static,
{
type Res = Res;
type Error = Err;
type Service = BoxService<St, Req, Res, Err>;
type InitError = InitErr;
#[inline]
async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
self.inner.create(st).await
}
}
impl<St, Req, Res, Err, InitErr> Clone for BoxServiceFactory<St, Req, Res, Err, InitErr> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl<St, Req, Res, Err, InitErr> fmt::Debug for BoxServiceFactory<St, Req, Res, Err, InitErr> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BoxServiceFactory").finish()
}
}
trait ServiceFactoryObj<St, Req> {
type Res;
type Error;
type InitErr;
fn create<'a>(
&'a self,
st: &'a St,
) -> BoxFuture<'a, Result<BoxService<St, Req, Self::Res, Self::Error>, Self::InitErr>>
where
Req: 'a;
}
impl<Sf, St, Req> ServiceFactoryObj<St, Req> for Sf
where
St: 'static,
Req: 'static,
Sf: ServiceFactory<St, Req> + 'static,
{
type Res = Sf::Res;
type Error = Sf::Error;
type InitErr = Sf::InitError;
#[inline]
fn create<'a>(
&'a self,
st: &'a St,
) -> BoxFuture<'a, Result<BoxService<St, Req, Self::Res, Self::Error>, Self::InitErr>>
where
Req: 'a,
{
let fut = ServiceFactory::create(self, st);
Box::pin(async move { fut.await.map(service) })
}
}