use crate::{ApiConnExt, FromConn};
use trillium::{async_trait, Conn, Handler};
#[async_trait]
pub trait TryFromConn: Send + Sync + Sized + 'static {
type Error: Send + Sync + Sized + 'static;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error>;
}
#[async_trait]
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
}
}
#[async_trait]
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(())
}
}
#[async_trait]
impl TryFromConn for Vec<u8> {
type Error = crate::Error;
async fn try_from_conn(conn: &mut Conn) -> Result<Self, Self::Error> {
conn.request_body()
.await
.read_bytes()
.await
.map_err(Into::into)
}
}
#[async_trait]
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")]
#[async_trait]
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)+) => (
#[async_trait]
impl<$($name),*> TryFromConn for ($($name,)*) where $($name: TryFromConn, <$name as TryFromConn>::Error: Handler),* {
type Error = Box<dyn Handler>;
#[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| Box::new(h) as Box<dyn Handler>)?;)*
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 }