use std::ops::{Deref, DerefMut};
use crate::Request;
use crate::outcome::try_outcome;
use crate::data::{Data, FromData, Outcome};
use crate::http::{RawStr, ext::IntoOwned};
use crate::form::parser::{Parser, RawStrParser, Buffer};
use crate::form::prelude::*;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Form<T>(T);
impl<T> Form<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> From<T> for Form<T> {
#[inline]
fn from(val: T) -> Form<T> {
Form(val)
}
}
impl<'r, T: FromForm<'r>> Form<T> {
#[inline]
pub fn parse(string: &'r str) -> Result<'r, T> {
Self::parse_iter(Form::values(string))
}
pub fn parse_iter<I>(fields: I) -> Result<'r, T>
where I: IntoIterator<Item = ValueField<'r>>
{
let mut ctxt = T::init(Options::Lenient);
fields.into_iter().for_each(|f| T::push_value(&mut ctxt, f));
T::finalize(ctxt)
}
}
impl<T: for<'a> FromForm<'a> + 'static> Form<T> {
pub fn parse_encoded(string: &RawStr) -> Result<'static, T> {
let buffer = Buffer::new();
let mut ctxt = T::init(Options::Lenient);
for field in RawStrParser::new(&buffer, string) {
T::push_value(&mut ctxt, field)
}
T::finalize(ctxt).map_err(|e| e.into_owned())
}
}
impl Form<()> {
pub fn values(string: &str) -> impl Iterator<Item = ValueField<'_>> {
string.split('&')
.filter(|s| !s.is_empty())
.map(ValueField::parse)
}
}
impl<T> Deref for Form<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Form<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[crate::async_trait]
impl<'r, T: FromForm<'r>> FromData<'r> for Form<T> {
type Error = Errors<'r>;
async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> Outcome<'r, Self> {
use either::Either;
let mut parser = try_outcome!(Parser::new(req, data).await);
let mut context = T::init(Options::Lenient);
while let Some(field) = parser.next().await {
match field {
Ok(Either::Left(value)) => T::push_value(&mut context, value),
Ok(Either::Right(data)) => T::push_data(&mut context, data).await,
Err(e) => T::push_error(&mut context, e),
}
}
match T::finalize(context) {
Ok(value) => Outcome::Success(Form(value)),
Err(e) => Outcome::Failure((e.status(), e)),
}
}
}