//! Trait object forms of services and service factories. use alloc::{boxed::Box, rc::Rc}; use core::{future::Future, pin::Pin}; use paste::paste; use crate::{Service, ServiceFactory}; /// A boxed future with no send bound or lifetime parameters. pub type BoxFuture = Pin>>; macro_rules! service_object { ($name: ident, $type: tt, $fn_name: ident) => { paste! { #[doc = "Type alias for service trait object using `" $type "`."] pub type $name = $type< dyn Service>>, >; #[doc = "Wraps service as a trait object using [`" $name "`]."] pub fn $fn_name(service: S) -> $name where S: Service + 'static, Req: 'static, S::Future: 'static, { $type::new(ServiceWrapper::new(service)) } } }; } service_object!(BoxService, Box, service); service_object!(RcService, Rc, rc_service); struct ServiceWrapper { inner: S, } impl ServiceWrapper { fn new(inner: S) -> Self { Self { inner } } } impl Service for ServiceWrapper where S: Service, S::Future: 'static, { type Response = Res; type Error = Err; type Future = BoxFuture>; crate::forward_ready!(inner); fn call(&self, req: Req) -> Self::Future { Box::pin(self.inner.call(req)) } } /// Wrapper for a service factory that will map it's services to boxed trait object services. pub struct BoxServiceFactory(Inner); /// Wraps a service factory that returns service trait objects. pub fn factory( factory: SF, ) -> BoxServiceFactory where SF: ServiceFactory + 'static, Req: 'static, SF::Response: 'static, SF::Service: 'static, SF::Future: 'static, SF::Error: 'static, SF::InitError: 'static, { BoxServiceFactory(Box::new(FactoryWrapper(factory))) } type Inner = Box< dyn ServiceFactory< Req, Config = C, Response = Res, Error = Err, InitError = InitErr, Service = BoxService, Future = BoxFuture, InitErr>>, >, >; impl ServiceFactory for BoxServiceFactory where Req: 'static, Res: 'static, Err: 'static, InitErr: 'static, { type Response = Res; type Error = Err; type Config = C; type Service = BoxService; type InitError = InitErr; type Future = BoxFuture>; fn new_service(&self, cfg: C) -> Self::Future { self.0.new_service(cfg) } } struct FactoryWrapper(SF); impl ServiceFactory for FactoryWrapper where Req: 'static, Res: 'static, Err: 'static, InitErr: 'static, SF: ServiceFactory, SF::Future: 'static, SF::Service: 'static, >::Future: 'static, { type Response = Res; type Error = Err; type Config = Cfg; type Service = BoxService; type InitError = InitErr; type Future = BoxFuture>; fn new_service(&self, cfg: Cfg) -> Self::Future { let f = self.0.new_service(cfg); Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) }) } }