use crate::http::{RawStr, Status};
use crate::request::{Request, local_cache};
use crate::data::{Data, Limits};
use crate::outcome::{self, IntoOutcome, try_outcome, Outcome::*};
pub type Outcome<'r, T, E = <T as FromData<'r>>::Error>
= outcome::Outcome<T, (Status, E), Data<'r>>;
impl<'r, S, E> IntoOutcome<S, (Status, E), Data<'r>> for Result<S, E> {
type Failure = Status;
type Forward = Data<'r>;
#[inline]
fn into_outcome(self, status: Status) -> Outcome<'r, S, E> {
match self {
Ok(val) => Success(val),
Err(err) => Failure((status, err))
}
}
#[inline]
fn or_forward(self, data: Data<'r>) -> Outcome<'r, S, E> {
match self {
Ok(val) => Success(val),
Err(_) => Forward(data)
}
}
}
#[crate::async_trait]
pub trait FromData<'r>: Sized {
type Error: Send + std::fmt::Debug;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self>;
}
use crate::data::Capped;
#[crate::async_trait]
impl<'r> FromData<'r> for Capped<String> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let limit = req.limits().get("string").unwrap_or(Limits::STRING);
data.open(limit).into_string().await.into_outcome(Status::BadRequest)
}
}
impl_strict_from_data_from_capped!(String);
#[crate::async_trait]
impl<'r> FromData<'r> for Capped<&'r str> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
let string = capped.map(|s| local_cache!(req, s).as_str());
Success(string)
}
}
impl_strict_from_data_from_capped!(&'r str);
#[crate::async_trait]
impl<'r> FromData<'r> for Capped<&'r RawStr> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
let raw = capped.map(|s| RawStr::new(local_cache!(req, s)));
Success(raw)
}
}
impl_strict_from_data_from_capped!(&'r RawStr);
#[crate::async_trait]
impl<'r> FromData<'r> for Capped<std::borrow::Cow<'_, str>> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<String>>::from_data(req, data).await);
Success(capped.map(|s| s.into()))
}
}
impl_strict_from_data_from_capped!(std::borrow::Cow<'_, str>);
#[crate::async_trait]
impl<'r> FromData<'r> for Capped<&'r [u8]> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let capped = try_outcome!(<Capped<Vec<u8>>>::from_data(req, data).await);
let raw = capped.map(|b| local_cache!(req, b).as_slice());
Success(raw)
}
}
impl_strict_from_data_from_capped!(&'r [u8]);
#[crate::async_trait]
impl<'r> FromData<'r> for Capped<Vec<u8>> {
type Error = std::io::Error;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
let limit = req.limits().get("bytes").unwrap_or(Limits::BYTES);
data.open(limit).into_bytes().await.into_outcome(Status::BadRequest)
}
}
impl_strict_from_data_from_capped!(Vec<u8>);
#[crate::async_trait]
impl<'r> FromData<'r> for Data<'r> {
type Error = std::convert::Infallible;
async fn from_data(_: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
Success(data)
}
}
#[crate::async_trait]
impl<'r, T: FromData<'r> + 'r> FromData<'r> for Result<T, T::Error> {
type Error = std::convert::Infallible;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
match T::from_data(req, data).await {
Success(v) => Success(Ok(v)),
Failure((_, e)) => Success(Err(e)),
Forward(d) => Forward(d),
}
}
}
#[crate::async_trait]
impl<'r, T: FromData<'r>> FromData<'r> for Option<T> {
type Error = std::convert::Infallible;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
match T::from_data(req, data).await {
Success(v) => Success(Some(v)),
Failure(..) | Forward(..) => Success(None),
}
}
}