#[cfg(any(feature = "serde_json", feature = "sonic-rs"))]
use crate::ApiConnExt;
use crate::FromConn;
use std::future::Future;
use trillium::{BoxedHandler, Conn, Handler};
pub trait TryFromConn: Send + Sync + Sized + 'static {
type Error: Send + Sync + Sized + 'static;
fn try_from_conn(conn: &mut Conn) -> impl Future<Output = Result<Self, Self::Error>> + Send;
}
#[cfg(feature = "serde_json")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde_json")))]
impl TryFromConn for serde_json::Value {
type Error = crate::Error;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
conn.deserialize().await
}
}
#[cfg(feature = "sonic-rs")]
#[cfg_attr(docsrs, doc(cfg(feature = "sonic-rs")))]
impl TryFromConn for sonic_rs::Value {
type Error = crate::Error;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
conn.deserialize().await
}
}
impl<T: FromConn> TryFromConn for T {
type Error = ();
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
Self::from_conn(conn).await.ok_or(())
}
}
impl TryFromConn for Vec<u8> {
type Error = crate::Error;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
conn.request_body().read_bytes().await.map_err(Into::into)
}
}
impl TryFromConn for String {
type Error = crate::Error;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
conn.request_body_string().await.map_err(Into::into)
}
}
#[cfg(feature = "url")]
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
impl TryFromConn for url::Url {
type Error = trillium::Status;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
let path = conn.path();
let host = conn
.request_headers()
.get_str(trillium::KnownHeaderName::Host)
.ok_or(trillium::Status::BadRequest)?;
let proto = if conn.is_secure() { "https" } else { "http" };
url::Url::parse(&format!("{proto}://{host}{path}"))
.map_err(|_| trillium::Status::BadRequest)
}
}
macro_rules! impl_try_from_conn_tuple {
($($name:ident)+) => (
impl<$($name),*> TryFromConn for ($($name,)*) where $($name: TryFromConn, <$name as TryFromConn>::Error: Handler),* {
type Error = BoxedHandler;
#[allow(non_snake_case)]
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
$(let $name = <$name as TryFromConn>::try_from_conn(conn)
.await
.map_err(|h| BoxedHandler::new(h))?;)*
Ok(($($name, )*))
}
}
)
}
impl_try_from_conn_tuple! { A B }
impl_try_from_conn_tuple! { A B C }
impl_try_from_conn_tuple! { A B C D }
impl_try_from_conn_tuple! { A B C D E }
impl_try_from_conn_tuple! { A B C D E F }
impl_try_from_conn_tuple! { A B C D E F G }
impl_try_from_conn_tuple! { A B C D E F G H }
impl_try_from_conn_tuple! { A B C D E F G H I }
impl_try_from_conn_tuple! { A B C D E F G H I J }
impl_try_from_conn_tuple! { A B C D E F G H I J K }
impl_try_from_conn_tuple! { A B C D E F G H I J K L }