1use core::{
4 convert::Infallible,
5 fmt,
6 marker::PhantomData,
7 ops::{Deref, DerefMut},
8};
9
10use serde_core::{de::Deserialize, ser::Serialize};
11use xitca_http::util::service::router::{PathGen, RouteGen, RouterMapErr};
12
13use crate::{
14 body::BodyStream,
15 context::WebContext,
16 error::{Error, error_from_service, forward_blank_bad_request},
17 handler::{FromRequest, Responder},
18 http::{WebResponse, const_header_value::JSON, header::CONTENT_TYPE},
19 service::Service,
20};
21
22use super::{
23 body::Limit,
24 header::{self, HeaderRef},
25};
26
27pub const DEFAULT_LIMIT: usize = 1024 * 1024;
28
29#[derive(Clone)]
34pub struct Json<T, const LIMIT: usize = DEFAULT_LIMIT>(pub T);
35
36impl<T, const LIMIT: usize> fmt::Debug for Json<T, LIMIT>
37where
38 T: fmt::Debug,
39{
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 f.debug_struct("Json")
42 .field("value", &self.0)
43 .field("limit", &LIMIT)
44 .finish()
45 }
46}
47
48impl<T, const LIMIT: usize> Deref for Json<T, LIMIT> {
49 type Target = T;
50
51 fn deref(&self) -> &Self::Target {
52 &self.0
53 }
54}
55
56impl<T, const LIMIT: usize> DerefMut for Json<T, LIMIT> {
57 fn deref_mut(&mut self) -> &mut Self::Target {
58 &mut self.0
59 }
60}
61
62impl<'a, 'r, C, B, T, const LIMIT: usize> FromRequest<'a, WebContext<'r, C, B>> for Json<T, LIMIT>
63where
64 B: BodyStream + Default,
65 T: for<'de> Deserialize<'de>,
66{
67 type Type<'b> = Json<T, LIMIT>;
68 type Error = Error;
69
70 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
71 HeaderRef::<'a, { header::CONTENT_TYPE }>::from_request(ctx).await?;
72 let (buf, _) = <(Vec<u8>, Limit<LIMIT>)>::from_request(ctx).await?;
73 serde_json::from_slice(&buf).map(Json).map_err(Into::into)
74 }
75}
76
77pub struct LazyJson<T, const LIMIT: usize = DEFAULT_LIMIT> {
110 bytes: Vec<u8>,
111 _json: PhantomData<T>,
112}
113
114impl<T, const LIMIT: usize> LazyJson<T, LIMIT> {
115 pub fn deserialize<'de>(&'de self) -> Result<T, Error>
116 where
117 T: Deserialize<'de>,
118 {
119 serde_json::from_slice(&self.bytes).map_err(Into::into)
120 }
121}
122
123impl<'a, 'r, C, B, T, const LIMIT: usize> FromRequest<'a, WebContext<'r, C, B>> for LazyJson<T, LIMIT>
124where
125 B: BodyStream + Default,
126 T: Deserialize<'static>,
127{
128 type Type<'b> = LazyJson<T, LIMIT>;
129 type Error = Error;
130
131 async fn from_request(ctx: &'a WebContext<'r, C, B>) -> Result<Self, Self::Error> {
132 HeaderRef::<'a, { header::CONTENT_TYPE }>::from_request(ctx).await?;
133 let (bytes, _) = <(Vec<u8>, Limit<LIMIT>)>::from_request(ctx).await?;
134 Ok(LazyJson {
135 bytes,
136 _json: PhantomData,
137 })
138 }
139}
140
141impl<'r, C, B, T> Responder<WebContext<'r, C, B>> for Json<T>
142where
143 T: Serialize,
144{
145 type Response = WebResponse;
146 type Error = Error;
147
148 #[inline]
149 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
150 self._respond(|buf| ctx.into_response(buf))
151 }
152
153 #[inline]
154 fn map(self, res: Self::Response) -> Result<Self::Response, Self::Error> {
155 self._respond(|buf| res.map(|_| buf.into()))
156 }
157}
158
159impl<T> Json<T> {
160 fn _respond<F>(self, func: F) -> Result<WebResponse, Error>
161 where
162 T: Serialize,
163 F: FnOnce(Vec<u8>) -> WebResponse,
164 {
165 let buf = serde_json::to_vec(&self.0)?;
166 let mut res = func(buf);
167 res.headers_mut().insert(CONTENT_TYPE, JSON);
168 Ok(res)
169 }
170}
171
172impl<'r, C, B> Responder<WebContext<'r, C, B>> for serde_json::Value {
173 type Response = WebResponse;
174 type Error = Error;
175
176 #[inline]
177 async fn respond(self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
178 Json(self).respond(ctx).await
179 }
180
181 #[inline]
182 fn map(self, res: Self::Response) -> Result<Self::Response, Self::Error> {
183 Responder::<WebContext<'r, C, B>>::map(Json(self), res)
184 }
185}
186
187error_from_service!(serde_json::Error);
188forward_blank_bad_request!(serde_json::Error);
189
190impl<T> PathGen for Json<T> {}
191
192impl<T> RouteGen for Json<T> {
193 type Route<R> = RouterMapErr<R>;
194
195 fn route_gen<R>(route: R) -> Self::Route<R> {
196 RouterMapErr(route)
197 }
198}
199
200impl<T> Service for Json<T>
201where
202 T: Clone,
203{
204 type Response = Self;
205 type Error = Infallible;
206
207 async fn call(&self, _: ()) -> Result<Self::Response, Self::Error> {
208 Ok(self.clone())
209 }
210}
211
212impl<'r, C, B, T> Service<WebContext<'r, C, B>> for Json<T>
213where
214 T: Serialize + Clone,
215{
216 type Response = WebResponse;
217 type Error = Error;
218
219 #[inline]
220 async fn call(&self, ctx: WebContext<'r, C, B>) -> Result<Self::Response, Self::Error> {
221 self.clone().respond(ctx).await
222 }
223}
224
225#[cfg(test)]
226mod test {
227 use xitca_unsafe_collection::futures::NowOrPanic;
228
229 use crate::{
230 App,
231 handler::handler_service,
232 http::{WebRequest, header::CONTENT_LENGTH},
233 test::collect_string_body,
234 };
235
236 use super::*;
237
238 #[derive(serde::Deserialize, serde::Serialize, Clone)]
239 struct Gacha<'a> {
240 credit_card: &'a str,
241 }
242
243 #[test]
244 fn extract_lazy() {
245 let mut ctx = WebContext::new_test(&());
246 let mut ctx = ctx.as_web_ctx();
247
248 let body = serde_json::to_string(&Gacha {
249 credit_card: "declined",
250 })
251 .unwrap();
252
253 ctx.req_mut().headers_mut().insert(CONTENT_TYPE, JSON);
254 ctx.req_mut().headers_mut().insert(CONTENT_LENGTH, body.len().into());
255
256 *ctx.body_borrow_mut() = body.into();
257
258 async fn handler(lazy: LazyJson<Gacha<'_>>) -> &'static str {
259 let ga = lazy.deserialize().unwrap();
260 assert_eq!(ga.credit_card, "declined");
261 "bankruptcy"
262 }
263
264 let service = handler_service(handler).call(()).now_or_panic().unwrap();
265
266 let body = service.call(ctx).now_or_panic().unwrap().into_body();
267 let res = collect_string_body(body).now_or_panic().unwrap();
268
269 assert_eq!(res, "bankruptcy");
270 }
271
272 #[test]
273 fn service() {
274 let res = App::new()
275 .at("/", Json(Gacha { credit_card: "mom" }))
276 .finish()
277 .call(())
278 .now_or_panic()
279 .unwrap()
280 .call(WebRequest::default())
281 .now_or_panic()
282 .unwrap();
283 assert_eq!(res.status().as_u16(), 200);
284 }
285}