request_pretreat/prefabs/
json.rs

1use std::{
2    fmt::{Debug, Display},
3    marker::PhantomData,
4    pin::Pin,
5    task::Poll,
6};
7
8use actix_web::{error::JsonPayloadError, web, FromRequest};
9use futures::{ready, Future};
10use pin_project::pin_project;
11
12use serde::Deserialize;
13
14use crate::Treater;
15
16use super::RawError;
17
18pub struct JsonPayload<T: for<'de> Deserialize<'de>>(PhantomData<T>);
19
20impl<T> Treater for JsonPayload<T>
21where
22    T: for<'de> Deserialize<'de>,
23{
24    type Fut = JsonTreaterFut<T>;
25
26    type Resp = T;
27
28    type Err = JsonError;
29
30    fn proc(req: &actix_web::HttpRequest, payload: &mut actix_web::dev::Payload) -> Self::Fut {
31        let task = web::Json::<T>::from_request(req, payload);
32        JsonTreaterFut { task }
33    }
34}
35
36pub struct JsonError(RawError<JsonPayloadError>);
37
38impl Debug for JsonError {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        Debug::fmt(&self.0, f)
41    }
42}
43
44impl Display for JsonError {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        Display::fmt(&self.0, f)
47    }
48}
49impl std::error::Error for JsonError {}
50
51#[pin_project]
52pub struct JsonTreaterFut<T>
53where
54    T: for<'de> Deserialize<'de>,
55{
56    #[pin]
57    task: <actix_web::web::Json<T> as FromRequest>::Future,
58}
59
60impl<T> Future for JsonTreaterFut<T>
61where
62    T: for<'de> Deserialize<'de>,
63{
64    type Output = Result<T, JsonError>;
65
66    fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
67        let this = self.project();
68
69        let result = ready!(this.task.poll(cx));
70
71        Poll::Ready(match result {
72            Ok(data) => Ok(data.into_inner()),
73            Err(err) => Err(JsonError(RawError::new(err))),
74        })
75    }
76}