trillium_api/
try_from_conn.rs1#[cfg(any(feature = "serde_json", feature = "sonic-rs"))]
2use crate::ApiConnExt;
3use crate::FromConn;
4use std::future::Future;
5use trillium::{BoxedHandler, Conn, Handler};
6
7pub trait TryFromConn: Send + Sync + Sized + 'static {
16 type Error: Send + Sync + Sized + 'static;
19
20 fn try_from_conn(conn: &mut Conn) -> impl Future<Output = Result<Self, Self::Error>> + Send;
22}
23
24#[cfg(feature = "serde_json")]
25#[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))]
26impl TryFromConn for serde_json::Value {
27 type Error = crate::Error;
28
29 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
30 conn.deserialize().await
31 }
32}
33
34#[cfg(feature = "sonic-rs")]
35#[cfg_attr(docsrs, doc(cfg(feature = "sonic-rs")))]
36impl TryFromConn for sonic_rs::Value {
37 type Error = crate::Error;
38
39 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
40 conn.deserialize().await
41 }
42}
43
44impl<T: FromConn> TryFromConn for T {
45 type Error = ();
46
47 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
48 Self::from_conn(conn).await.ok_or(())
49 }
50}
51
52impl TryFromConn for Vec<u8> {
53 type Error = crate::Error;
54
55 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
56 conn.request_body().read_bytes().await.map_err(Into::into)
57 }
58}
59
60impl TryFromConn for String {
61 type Error = crate::Error;
62
63 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
64 conn.request_body_string().await.map_err(Into::into)
65 }
66}
67
68#[cfg(feature = "url")]
69#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
70impl TryFromConn for url::Url {
71 type Error = trillium::Status;
72
73 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
74 let path = conn.path();
75 let host = conn
76 .request_headers()
77 .get_str(trillium::KnownHeaderName::Host)
78 .ok_or(trillium::Status::BadRequest)?;
79 let proto = if conn.is_secure() { "https" } else { "http" };
80 url::Url::parse(&format!("{proto}://{host}{path}"))
81 .map_err(|_| trillium::Status::BadRequest)
82 }
83}
84
85macro_rules! impl_try_from_conn_tuple {
86 ($($name:ident)+) => (
87 impl<$($name),*> TryFromConn for ($($name,)*) where $($name: TryFromConn, <$name as TryFromConn>::Error: Handler),* {
88 type Error = BoxedHandler;
89 #[allow(non_snake_case)]
90 async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
91 $(let $name = <$name as TryFromConn>::try_from_conn(conn)
92 .await
93 .map_err(|h| BoxedHandler::new(h))?;)*
94 Ok(($($name, )*))
95 }
96 }
97 )
98}
99
100impl_try_from_conn_tuple! { A B }
101impl_try_from_conn_tuple! { A B C }
102impl_try_from_conn_tuple! { A B C D }
103impl_try_from_conn_tuple! { A B C D E }
104impl_try_from_conn_tuple! { A B C D E F }
105impl_try_from_conn_tuple! { A B C D E F G }
106impl_try_from_conn_tuple! { A B C D E F G H }
107impl_try_from_conn_tuple! { A B C D E F G H I }
108impl_try_from_conn_tuple! { A B C D E F G H I J }
109impl_try_from_conn_tuple! { A B C D E F G H I J K }
110impl_try_from_conn_tuple! { A B C D E F G H I J K L }