actix_service/
boxed.rs

1//! Trait object forms of services and service factories.
2
3use alloc::{boxed::Box, rc::Rc};
4use core::{future::Future, pin::Pin};
5
6use crate::{Service, ServiceFactory};
7
8/// A boxed future with no send bound or lifetime parameters.
9pub type BoxFuture<T> = Pin<Box<dyn Future<Output = T>>>;
10
11/// Type alias for service trait object using [`Box`].
12pub type BoxService<Req, Res, Err> =
13    Box<dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<Result<Res, Err>>>>;
14
15/// Wraps service as a trait object using [`BoxService`].
16pub fn service<S, Req>(service: S) -> BoxService<Req, S::Response, S::Error>
17where
18    S: Service<Req> + 'static,
19    Req: 'static,
20    S::Future: 'static,
21{
22    Box::new(ServiceWrapper::new(service))
23}
24
25/// Type alias for service trait object using [`Rc`].
26pub type RcService<Req, Res, Err> =
27    Rc<dyn Service<Req, Response = Res, Error = Err, Future = BoxFuture<Result<Res, Err>>>>;
28
29/// Wraps service as a trait object using [`RcService`].
30pub fn rc_service<S, Req>(service: S) -> RcService<Req, S::Response, S::Error>
31where
32    S: Service<Req> + 'static,
33    Req: 'static,
34    S::Future: 'static,
35{
36    Rc::new(ServiceWrapper::new(service))
37}
38
39struct ServiceWrapper<S> {
40    inner: S,
41}
42
43impl<S> ServiceWrapper<S> {
44    fn new(inner: S) -> Self {
45        Self { inner }
46    }
47}
48
49impl<S, Req, Res, Err> Service<Req> for ServiceWrapper<S>
50where
51    S: Service<Req, Response = Res, Error = Err>,
52    S::Future: 'static,
53{
54    type Response = Res;
55    type Error = Err;
56    type Future = BoxFuture<Result<Res, Err>>;
57
58    crate::forward_ready!(inner);
59
60    fn call(&self, req: Req) -> Self::Future {
61        Box::pin(self.inner.call(req))
62    }
63}
64
65/// Wrapper for a service factory that will map it's services to boxed trait object services.
66pub struct BoxServiceFactory<Cfg, Req, Res, Err, InitErr>(Inner<Cfg, Req, Res, Err, InitErr>);
67
68/// Wraps a service factory that returns service trait objects.
69pub fn factory<SF, Req>(
70    factory: SF,
71) -> BoxServiceFactory<SF::Config, Req, SF::Response, SF::Error, SF::InitError>
72where
73    SF: ServiceFactory<Req> + 'static,
74    Req: 'static,
75    SF::Response: 'static,
76    SF::Service: 'static,
77    SF::Future: 'static,
78    SF::Error: 'static,
79    SF::InitError: 'static,
80{
81    BoxServiceFactory(Box::new(FactoryWrapper(factory)))
82}
83
84type Inner<C, Req, Res, Err, InitErr> = Box<
85    dyn ServiceFactory<
86        Req,
87        Config = C,
88        Response = Res,
89        Error = Err,
90        InitError = InitErr,
91        Service = BoxService<Req, Res, Err>,
92        Future = BoxFuture<Result<BoxService<Req, Res, Err>, InitErr>>,
93    >,
94>;
95
96impl<C, Req, Res, Err, InitErr> ServiceFactory<Req> for BoxServiceFactory<C, Req, Res, Err, InitErr>
97where
98    Req: 'static,
99    Res: 'static,
100    Err: 'static,
101    InitErr: 'static,
102{
103    type Response = Res;
104    type Error = Err;
105    type Config = C;
106    type Service = BoxService<Req, Res, Err>;
107    type InitError = InitErr;
108
109    type Future = BoxFuture<Result<Self::Service, InitErr>>;
110
111    fn new_service(&self, cfg: C) -> Self::Future {
112        self.0.new_service(cfg)
113    }
114}
115
116struct FactoryWrapper<SF>(SF);
117
118impl<SF, Req, Cfg, Res, Err, InitErr> ServiceFactory<Req> for FactoryWrapper<SF>
119where
120    Req: 'static,
121    Res: 'static,
122    Err: 'static,
123    InitErr: 'static,
124    SF: ServiceFactory<Req, Config = Cfg, Response = Res, Error = Err, InitError = InitErr>,
125    SF::Future: 'static,
126    SF::Service: 'static,
127    <SF::Service as Service<Req>>::Future: 'static,
128{
129    type Response = Res;
130    type Error = Err;
131    type Config = Cfg;
132    type Service = BoxService<Req, Res, Err>;
133    type InitError = InitErr;
134    type Future = BoxFuture<Result<Self::Service, Self::InitError>>;
135
136    fn new_service(&self, cfg: Cfg) -> Self::Future {
137        let f = self.0.new_service(cfg);
138        Box::pin(async { f.await.map(|s| Box::new(ServiceWrapper::new(s)) as _) })
139    }
140}