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