xitca_web/service/
tower_http_compat.rs1use core::{
2 cell::RefCell,
3 convert::Infallible,
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use std::borrow::Cow;
9
10use pin_project_lite::pin_project;
11use xitca_http::util::service::router::{PathGen, RouteGen, RouterMapErr};
12use xitca_unsafe_collection::fake::{FakeSend, FakeSync};
13
14use crate::{
15 body::{Body, Frame, ResponseBody, SizeHint},
16 bytes::{Buf, Bytes, BytesMut},
17 context::WebContext,
18 http::{Request, RequestExt, Response, WebResponse},
19 service::{Service, ready::ReadyService},
20};
21
22pub struct TowerHttpCompat<S>(S);
25
26impl<S> TowerHttpCompat<S> {
27 pub const fn new(service: S) -> Self
28 where
29 S: Clone,
30 {
31 Self(service)
32 }
33}
34
35impl<S> Service for TowerHttpCompat<S>
36where
37 S: Clone,
38{
39 type Response = TowerCompatService<S>;
40 type Error = Infallible;
41
42 async fn call(&self, _: ()) -> Result<Self::Response, Self::Error> {
43 let service = self.0.clone();
44 Ok(TowerCompatService(RefCell::new(service)))
45 }
46}
47
48impl<S> PathGen for TowerHttpCompat<S> {}
49
50impl<S> RouteGen for TowerHttpCompat<S> {
51 type Route<R> = RouterMapErr<R>;
52
53 fn route_gen<R>(route: R) -> Self::Route<R> {
54 RouterMapErr(route)
55 }
56}
57
58pub struct TowerCompatService<S>(RefCell<S>);
59
60impl<S> TowerCompatService<S> {
61 pub const fn new(service: S) -> Self {
62 Self(RefCell::new(service))
63 }
64}
65
66impl<'r, C, ReqB, S, ResB> Service<WebContext<'r, C, ReqB>> for TowerCompatService<S>
67where
68 S: tower_service::Service<Request<CompatReqBody<RequestExt<ReqB>, C>>, Response = Response<ResB>>,
69 ResB: http_body::Body,
70 C: Clone + 'static,
71 ReqB: Default,
72{
73 type Response = WebResponse<CompatBody<ResB>>;
74 type Error = S::Error;
75
76 async fn call(&self, mut ctx: WebContext<'r, C, ReqB>) -> Result<Self::Response, Self::Error> {
77 let (parts, ext) = ctx.take_request().into_parts();
78 let ctx = ctx.state().clone();
79 let req = Request::from_parts(parts, CompatReqBody::new(ext, ctx));
80 let fut = tower_service::Service::call(&mut *self.0.borrow_mut(), req);
81 fut.await.map(|res| res.map(CompatBody::new))
82 }
83}
84
85impl<S> ReadyService for TowerCompatService<S> {
86 type Ready = ();
87
88 #[inline]
89 async fn ready(&self) -> Self::Ready {}
90}
91
92pub struct CompatReqBody<B, C> {
93 body: FakeSend<CompatBody<B>>,
94 ctx: FakeSend<FakeSync<C>>,
95}
96
97impl<B, C> CompatReqBody<B, C> {
98 #[inline]
99 pub fn new(body: B, ctx: C) -> Self {
100 Self {
101 body: FakeSend::new(CompatBody::new(body)),
102 ctx: FakeSend::new(FakeSync::new(ctx)),
103 }
104 }
105
106 #[inline]
111 pub fn into_parts(self) -> (B, C) {
112 (self.body.into_inner().into_inner(), self.ctx.into_inner().into_inner())
113 }
114}
115
116impl<B, C> http_body::Body for CompatReqBody<B, C>
117where
118 B: Body + Unpin,
119 C: Unpin,
120 B::Data: Buf,
121{
122 type Data = B::Data;
123 type Error = B::Error;
124
125 #[inline]
126 fn poll_frame(
127 self: Pin<&mut Self>,
128 cx: &mut Context<'_>,
129 ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
130 http_body::Body::poll_frame(Pin::new(&mut *self.get_mut().body), cx)
131 }
132
133 #[inline]
134 fn size_hint(&self) -> http_body::SizeHint {
135 http_body::Body::size_hint(&*self.body)
136 }
137}
138
139pin_project! {
140 #[derive(Default)]
141 pub struct CompatBody<B> {
142 #[pin]
143 body: B
144 }
145}
146
147impl<B> CompatBody<B> {
148 pub const fn new(body: B) -> Self {
149 Self { body }
150 }
151
152 pub fn into_inner(self) -> B {
153 self.body
154 }
155}
156
157macro_rules! impl_from {
159 ($ty: ty) => {
160 impl<B> From<$ty> for CompatBody<B>
161 where
162 B: From<$ty>,
163 {
164 fn from(body: $ty) -> Self {
165 Self::new(B::from(body))
166 }
167 }
168 };
169}
170
171impl_from!(Bytes);
172impl_from!(BytesMut);
173impl_from!(&'static [u8]);
174impl_from!(&'static str);
175impl_from!(Box<[u8]>);
176impl_from!(Vec<u8>);
177impl_from!(String);
178impl_from!(Box<str>);
179impl_from!(Cow<'static, str>);
180impl_from!(ResponseBody);
181
182impl<B> http_body::Body for CompatBody<B>
183where
184 B: Body,
185 B::Data: Buf,
186{
187 type Data = B::Data;
188 type Error = B::Error;
189
190 #[inline]
191 fn poll_frame(
192 self: Pin<&mut Self>,
193 cx: &mut Context<'_>,
194 ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
195 Body::poll_frame(self.project().body, cx).map_ok(|frame| match frame {
196 Frame::Data(data) => http_body::Frame::data(data),
197 Frame::Trailers(trailers) => http_body::Frame::trailers(trailers),
198 })
199 }
200
201 #[inline]
202 fn is_end_stream(&self) -> bool {
203 Body::is_end_stream(&self.body)
204 }
205
206 #[inline]
207 fn size_hint(&self) -> http_body::SizeHint {
208 match Body::size_hint(&self.body) {
209 SizeHint::Exact(size) => http_body::SizeHint::with_exact(size),
210 _ => http_body::SizeHint::default(),
211 }
212 }
213}
214
215impl<B> Body for CompatBody<B>
216where
217 B: http_body::Body,
218{
219 type Data = B::Data;
220 type Error = B::Error;
221
222 #[inline]
223 fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
224 http_body::Body::poll_frame(self.project().body, cx).map_ok(|frame| match frame.into_data() {
225 Ok(data) => Frame::Data(data),
226 Err(frame) => Frame::Trailers(frame.into_trailers().ok().unwrap()),
227 })
228 }
229
230 #[inline]
231 fn is_end_stream(&self) -> bool {
232 http_body::Body::is_end_stream(&self.body)
233 }
234
235 #[inline]
236 fn size_hint(&self) -> SizeHint {
237 match http_body::Body::size_hint(&self.body).exact() {
238 Some(size) => SizeHint::Exact(size),
239 None => SizeHint::Unknown,
240 }
241 }
242}