Skip to main content

ntex_service/
boxed.rs

1use std::{fmt, rc::Rc};
2
3use crate::ctx::{Ctx, WaitersRef};
4use crate::{Service, ServiceFactory, util::BoxFuture};
5
6// ============================ Service =============================
7
8/// Boxed service.
9pub struct BoxService<St, Req, Res, Err> {
10    inner: Rc<dyn ServiceObj<St, Req, Res = Res, Error = Err>>,
11}
12
13/// Creates a boxed service.
14pub fn service<S, St, Req, Res, Err>(service: S) -> BoxService<St, Req, Res, Err>
15where
16    S: Service<St, Req, Res = Res, Error = Err> + 'static,
17{
18    BoxService::new(service)
19}
20
21impl<St, Req, Res, Err> BoxService<St, Req, Res, Err> {
22    /// Creates a boxed service.
23    pub fn new<S>(service: S) -> Self
24    where
25        S: Service<St, Req, Res = Res, Error = Err> + 'static,
26    {
27        BoxService {
28            inner: Rc::new(service),
29        }
30    }
31}
32
33impl<St, Req, Res, Err> Clone for BoxService<St, Req, Res, Err> {
34    fn clone(&self) -> Self {
35        Self {
36            inner: self.inner.clone(),
37        }
38    }
39}
40
41impl<St, Req, Res, Err> fmt::Debug for BoxService<St, Req, Res, Err> {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        f.debug_struct("BoxService").finish()
44    }
45}
46
47impl<St, Req, Res, Err> Service<St, Req> for BoxService<St, Req, Res, Err> {
48    type Res = Res;
49    type Error = Err;
50
51    #[inline]
52    async fn ready(&self, ctx: Ctx<'_, Self, St>) -> Result<(), Self::Error> {
53        let (idx, waiters, st) = ctx.inner();
54        self.inner.ready(idx, waiters, st).await
55    }
56
57    #[inline]
58    async fn call(&self, req: Req, ctx: Ctx<'_, Self, St>) -> Result<Res, Err> {
59        let (idx, waiters, st) = ctx.inner();
60        self.inner.call(req, idx, waiters, st).await
61    }
62
63    #[inline]
64    async fn shutdown(&self, ctx: Ctx<'_, Self, St>) {
65        let (idx, waiters, st) = ctx.inner();
66        self.inner.shutdown(idx, waiters, st).await;
67    }
68}
69
70trait ServiceObj<St, Req> {
71    type Res;
72    type Error;
73
74    fn ready<'a>(
75        &'a self,
76        i: u32,
77        w: &'a WaitersRef,
78        s: &'a St,
79    ) -> BoxFuture<'a, Result<(), Self::Error>>;
80
81    fn call<'a>(
82        &'a self,
83        r: Req,
84        i: u32,
85        w: &'a WaitersRef,
86        s: &'a St,
87    ) -> BoxFuture<'a, Result<Self::Res, Self::Error>>
88    where
89        Req: 'a;
90
91    fn shutdown<'a>(&'a self, idx: u32, waiters: &'a WaitersRef, st: &'a St) -> BoxFuture<'a, ()>
92    where
93        St: 'a,
94        Req: 'a;
95}
96
97impl<S, St, Req> ServiceObj<St, Req> for S
98where
99    S: Service<St, Req>,
100{
101    type Res = S::Res;
102    type Error = S::Error;
103
104    #[inline]
105    fn ready<'a>(
106        &'a self,
107        idx: u32,
108        waiters: &'a WaitersRef,
109        st: &'a St,
110    ) -> BoxFuture<'a, Result<(), Self::Error>> {
111        Box::pin(async move { Ctx::<'a, S, St>::new(idx, waiters, st).ready(self).await })
112    }
113
114    #[inline]
115    fn call<'a>(
116        &'a self,
117        req: Req,
118        idx: u32,
119        waiters: &'a WaitersRef,
120        st: &'a St,
121    ) -> BoxFuture<'a, Result<S::Res, S::Error>>
122    where
123        Req: 'a,
124    {
125        Box::pin(async move {
126            Ctx::<'a, S, St>::new(idx, waiters, st)
127                .call_nowait(self, req)
128                .await
129        })
130    }
131
132    #[inline]
133    fn shutdown<'a>(&'a self, idx: u32, waiters: &'a WaitersRef, st: &'a St) -> BoxFuture<'a, ()>
134    where
135        St: 'a,
136        Req: 'a,
137    {
138        Box::pin(async move { Ctx::<'a, S, St>::new(idx, waiters, st).shutdown(self).await })
139    }
140}
141
142// ============================ ServiceFactory =============================
143
144/// Boxed service factory.
145pub struct BoxServiceFactory<St, Req, Res, Err, InitErr> {
146    inner: Rc<dyn ServiceFactoryObj<St, Req, Res = Res, Error = Err, InitErr = InitErr>>,
147}
148
149/// Creates a boxed service factory.
150pub fn factory<Sf, St, Req>(
151    factory: Sf,
152) -> BoxServiceFactory<St, Req, Sf::Res, Sf::Error, Sf::InitError>
153where
154    Sf: ServiceFactory<St, Req> + 'static,
155    St: 'static,
156    Req: 'static,
157{
158    BoxServiceFactory::new(factory)
159}
160
161impl<St, Req, Res, Err, InitErr> BoxServiceFactory<St, Req, Res, Err, InitErr>
162where
163    St: 'static,
164    Req: 'static,
165{
166    /// Creates a boxed service factory.
167    pub fn new<Sf>(factory: Sf) -> Self
168    where
169        Sf: ServiceFactory<St, Req, Res = Res, Error = Err, InitError = InitErr> + 'static,
170        St: 'static,
171        Req: 'static,
172    {
173        Self {
174            inner: Rc::new(factory),
175        }
176    }
177}
178
179impl<St, Req, Res, Err, InitErr> ServiceFactory<St, Req>
180    for BoxServiceFactory<St, Req, Res, Err, InitErr>
181where
182    Req: 'static,
183{
184    type Res = Res;
185    type Error = Err;
186
187    type Service = BoxService<St, Req, Res, Err>;
188    type InitError = InitErr;
189
190    #[inline]
191    async fn create(&self, st: &St) -> Result<Self::Service, Self::InitError> {
192        self.inner.create(st).await
193    }
194}
195
196impl<St, Req, Res, Err, InitErr> Clone for BoxServiceFactory<St, Req, Res, Err, InitErr> {
197    fn clone(&self) -> Self {
198        Self {
199            inner: self.inner.clone(),
200        }
201    }
202}
203
204impl<St, Req, Res, Err, InitErr> fmt::Debug for BoxServiceFactory<St, Req, Res, Err, InitErr> {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        f.debug_struct("BoxServiceFactory").finish()
207    }
208}
209
210trait ServiceFactoryObj<St, Req> {
211    type Res;
212    type Error;
213    type InitErr;
214
215    fn create<'a>(
216        &'a self,
217        st: &'a St,
218    ) -> BoxFuture<'a, Result<BoxService<St, Req, Self::Res, Self::Error>, Self::InitErr>>
219    where
220        Req: 'a;
221}
222
223impl<Sf, St, Req> ServiceFactoryObj<St, Req> for Sf
224where
225    St: 'static,
226    Req: 'static,
227    Sf: ServiceFactory<St, Req> + 'static,
228{
229    type Res = Sf::Res;
230    type Error = Sf::Error;
231    type InitErr = Sf::InitError;
232
233    #[inline]
234    fn create<'a>(
235        &'a self,
236        st: &'a St,
237    ) -> BoxFuture<'a, Result<BoxService<St, Req, Self::Res, Self::Error>, Self::InitErr>>
238    where
239        Req: 'a,
240    {
241        let fut = ServiceFactory::create(self, st);
242        Box::pin(async move { fut.await.map(service) })
243    }
244}