1use std::{
2 any::{Any, TypeId},
3 future::Future,
4 marker::PhantomData,
5 pin::Pin,
6};
7
8use crate::{AsyncMakeService, MakeService, Service};
9pub struct BoxedService<Request, Response, E> {
13 svc: *const (),
14 type_id: TypeId,
15 vtable: ServiceVtable<Request, Response, E>,
16}
17
18impl<Request, Response, E> BoxedService<Request, Response, E> {
19 pub fn new<S>(s: S) -> Self
20 where
21 S: Service<Request, Response = Response, Error = E> + 'static,
22 Request: 'static,
23 {
24 let type_id = s.type_id();
25 let svc = Box::into_raw(Box::new(s)) as *const ();
26 BoxedService {
27 svc,
28 type_id,
29 vtable: ServiceVtable {
30 call: call::<Request, S>,
31 drop: drop::<S>,
32 },
33 }
34 }
35
36 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
37 let t = TypeId::of::<T>();
38 if self.type_id == t {
39 Some(unsafe { self.downcast_ref_unchecked() })
40 } else {
41 None
42 }
43 }
44
45 pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
48 &*(self.svc as *const T)
49 }
50}
51
52impl<Request, Response, E> Drop for BoxedService<Request, Response, E> {
53 #[inline]
54 fn drop(&mut self) {
55 unsafe { (self.vtable.drop)(self.svc) };
56 }
57}
58
59impl<Request, Response, E> Service<Request> for BoxedService<Request, Response, E> {
60 type Response = Response;
61 type Error = E;
62
63 #[inline]
64 fn call(&self, req: Request) -> impl Future<Output = Result<Self::Response, Self::Error>> {
65 unsafe { (self.vtable.call)(self.svc, req) }
66 }
67}
68
69pub trait BoxService<Request, Response, E> {
74 fn into_boxed(self) -> BoxedService<Request, Response, E>;
75}
76
77impl<T, Request, Response, E> BoxService<Request, Response, E> for T
78where
79 T: Service<Request, Response = Response, Error = E> + 'static,
80 Request: 'static,
81{
82 fn into_boxed(self) -> BoxedService<Request, Response, E> {
83 BoxedService::new(self)
84 }
85}
86
87type LocalStaticBoxedFuture<T, E> = Pin<Box<dyn Future<Output = Result<T, E>> + 'static>>;
88
89struct ServiceVtable<T, U, E> {
90 call: unsafe fn(raw: *const (), req: T) -> LocalStaticBoxedFuture<U, E>,
91 drop: unsafe fn(raw: *const ()),
92}
93
94unsafe fn call<R, S>(svc: *const (), req: R) -> LocalStaticBoxedFuture<S::Response, S::Error>
95where
96 R: 'static,
97 S: Service<R> + 'static,
98{
99 let svc = &*svc.cast::<S>();
100 let fut = S::call(svc, req);
101 Box::pin(fut)
102}
103
104unsafe fn drop<S>(raw: *const ()) {
105 std::ptr::drop_in_place(raw as *mut S);
106}
107
108pub struct BoxServiceFactory<F, Req> {
113 pub inner: F,
114 _marker: PhantomData<Req>,
115}
116
117unsafe impl<F: Send, Req> Send for BoxServiceFactory<F, Req> {}
118
119unsafe impl<F: Sync, Req> Sync for BoxServiceFactory<F, Req> {}
120
121impl<F, Req> BoxServiceFactory<F, Req> {
122 pub fn new(inner: F) -> Self {
123 BoxServiceFactory {
124 inner,
125 _marker: PhantomData,
126 }
127 }
128}
129
130impl<F, Req> MakeService for BoxServiceFactory<F, Req>
131where
132 F: MakeService,
133 F::Service: Service<Req> + 'static,
134 Req: 'static,
135{
136 type Service = BoxedService<
137 Req,
138 <F::Service as Service<Req>>::Response,
139 <F::Service as Service<Req>>::Error,
140 >;
141 type Error = F::Error;
142
143 fn make_via_ref(&self, old: Option<&Self::Service>) -> Result<Self::Service, Self::Error> {
144 let svc = match old {
145 Some(inner) => self.inner.make_via_ref(inner.downcast_ref())?,
146 None => self.inner.make()?,
147 };
148 Ok(svc.into_boxed())
149 }
150}
151
152impl<F, Req> AsyncMakeService for BoxServiceFactory<F, Req>
153where
154 F: AsyncMakeService,
155 F::Service: Service<Req> + 'static,
156 Req: 'static,
157{
158 type Service = BoxedService<
159 Req,
160 <F::Service as Service<Req>>::Response,
161 <F::Service as Service<Req>>::Error,
162 >;
163 type Error = F::Error;
164
165 async fn make_via_ref(
166 &self,
167 old: Option<&Self::Service>,
168 ) -> Result<Self::Service, Self::Error> {
169 let svc = match old {
170 Some(inner) => self.inner.make_via_ref(inner.downcast_ref()).await?,
171 None => self.inner.make().await?,
172 };
173 Ok(svc.into_boxed())
174 }
175}
176pub struct BoxedAsyncMakeService<S, E> {
181 svc: *const (),
182 type_id: TypeId,
183 vtable: AsyncMakeServiceVtable<S, E>,
184}
185
186unsafe impl<S, E> Send for BoxedAsyncMakeService<S, E> {}
187unsafe impl<S, E> Sync for BoxedAsyncMakeService<S, E> {}
188
189impl<S, E> BoxedAsyncMakeService<S, E> {
190 pub fn new<AMS>(ams: AMS) -> Self
191 where
192 AMS: AsyncMakeService<Service = S, Error = E> + Send + Sync + 'static,
193 S: 'static,
194 {
195 let type_id = ams.type_id();
196 let svc = Box::into_raw(Box::new(ams)) as *const ();
197 BoxedAsyncMakeService {
198 svc,
199 type_id,
200 vtable: AsyncMakeServiceVtable {
201 make_via_ref: make_via_ref::<AMS, S, E>,
202 drop: drop::<AMS>,
203 },
204 }
205 }
206
207 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
208 let t = TypeId::of::<T>();
209 if self.type_id == t {
210 Some(unsafe { self.downcast_ref_unchecked() })
211 } else {
212 None
213 }
214 }
215
216 pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T {
219 &*(self.svc as *const T)
220 }
221}
222
223impl<S, E> Drop for BoxedAsyncMakeService<S, E> {
224 #[inline]
225 fn drop(&mut self) {
226 unsafe { (self.vtable.drop)(self.svc) };
227 }
228}
229
230impl<S, E> AsyncMakeService for BoxedAsyncMakeService<S, E> {
231 type Service = S;
232 type Error = E;
233
234 #[inline]
235 async fn make_via_ref(
236 &self,
237 old: Option<&Self::Service>,
238 ) -> Result<Self::Service, Self::Error> {
239 unsafe { (self.vtable.make_via_ref)(self.svc, old.map(|s| s as _)) }.await
240 }
241}
242
243type LocalBoxedFuture<T, E> = Pin<Box<dyn Future<Output = Result<T, E>>>>;
244
245struct AsyncMakeServiceVtable<S, E> {
246 make_via_ref: unsafe fn(raw: *const (), old: Option<*const S>) -> LocalBoxedFuture<S, E>,
247 drop: unsafe fn(raw: *const ()),
248}
249
250unsafe fn make_via_ref<AMS, S, E>(
251 svc: *const (),
252 old: Option<*const AMS::Service>,
253) -> LocalBoxedFuture<S, E>
254where
255 AMS: AsyncMakeService<Service = S, Error = E> + 'static,
256 S: 'static,
257{
258 let svc = &*svc.cast::<AMS>();
259 let fut = AMS::make_via_ref(svc, old.map(|s| unsafe { &*s }));
260 Box::pin(fut)
261}