Don't include generic in error type

This commit is contained in:
Aode (Lion) 2021-09-13 20:45:09 -05:00
parent 1e635ce27c
commit d83b0ad464
8 changed files with 63 additions and 74 deletions

View file

@ -1,7 +1,7 @@
[package] [package]
name = "actix-form-data" name = "actix-form-data"
description = "Multipart Form Data for Actix Web" description = "Multipart Form Data for Actix Web"
version = "0.6.0-beta.8" version = "0.6.0-beta.9"
license = "GPL-3.0" license = "GPL-3.0"
authors = ["asonix <asonix@asonix.dog>"] authors = ["asonix <asonix@asonix.dog>"]
repository = "https://git.asonix.dog/Aardwolf/actix-form-data.git" repository = "https://git.asonix.dog/Aardwolf/actix-form-data.git"

View file

@ -1,24 +1,10 @@
use actix_form_data::{Field, Form, Value}; use actix_form_data::{Error, Field, Form, Value};
use actix_web::{ use actix_web::{
web::{post, resource}, web::{post, resource},
App, HttpResponse, HttpServer, ResponseError, App, HttpResponse, HttpServer,
}; };
use futures_util::stream::StreamExt; use futures_util::stream::StreamExt;
#[derive(Debug, thiserror::Error)]
#[error("{inner}")]
struct MyError {
inner: Box<dyn std::error::Error + 'static>,
}
impl MyError {
fn new(e: impl std::error::Error + 'static) -> Self {
Self { inner: Box::new(e) }
}
}
impl ResponseError for MyError {}
async fn upload(uploaded_content: Value<()>) -> HttpResponse { async fn upload(uploaded_content: Value<()>) -> HttpResponse {
println!("Uploaded Content: {:#?}", uploaded_content); println!("Uploaded Content: {:#?}", uploaded_content);
HttpResponse::Created().finish() HttpResponse::Created().finish()
@ -39,9 +25,9 @@ async fn main() -> Result<(), anyhow::Error> {
"files", "files",
Field::array(Field::file(|_, _, mut stream| async move { Field::array(Field::file(|_, _, mut stream| async move {
while let Some(res) = stream.next().await { while let Some(res) = stream.next().await {
res.map_err(MyError::new)?; res?;
} }
Ok(()) as Result<(), MyError> Ok(()) as Result<(), Error>
})), })),
); );

View file

@ -67,7 +67,7 @@ async fn upload(uploaded_content: Value<PathBuf>) -> HttpResponse {
} }
async fn save_file( async fn save_file(
stream: Pin<Box<dyn Stream<Item = Result<Bytes, Error<Errors>>>>>, stream: Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>,
count: usize, count: usize,
) -> Result<String, JsonError> { ) -> Result<String, JsonError> {
use futures_lite::io::AsyncWriteExt; use futures_lite::io::AsyncWriteExt;

View file

@ -30,9 +30,7 @@ use actix_web::{
}; };
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error<E> { pub enum Error {
#[error("{0}")]
FileFn(E),
#[error("Error parsing payload, {0}")] #[error("Error parsing payload, {0}")]
Payload(#[from] PayloadError), Payload(#[from] PayloadError),
#[error("Error in multipart creation, {0}")] #[error("Error in multipart creation, {0}")]
@ -63,19 +61,15 @@ pub enum Error<E> {
FileSize, FileSize,
} }
impl<E> From<MultipartError> for Error<E> { impl From<MultipartError> for Error {
fn from(m: MultipartError) -> Self { fn from(m: MultipartError) -> Self {
Error::Multipart(m) Error::Multipart(m)
} }
} }
impl<E> ResponseError for Error<E> impl ResponseError for Error {
where
E: ResponseError,
{
fn status_code(&self) -> StatusCode { fn status_code(&self) -> StatusCode {
match *self { match *self {
Error::FileFn(ref e) => e.status_code(),
Error::Payload(ref e) => e.status_code(), Error::Payload(ref e) => e.status_code(),
_ => StatusCode::BAD_REQUEST, _ => StatusCode::BAD_REQUEST,
} }
@ -83,7 +77,6 @@ where
fn error_response(&self) -> HttpResponse { fn error_response(&self) -> HttpResponse {
match *self { match *self {
Error::FileFn(ref e) => e.error_response(),
Error::Payload(ref e) => e.error_response(), Error::Payload(ref e) => e.error_response(),
Error::Multipart(_) Error::Multipart(_)
| Error::ParseField(_) | Error::ParseField(_)

View file

@ -54,7 +54,7 @@
//! while let Some(_) = stream.next().await { //! while let Some(_) = stream.next().await {
//! // do something //! // do something
//! } //! }
//! Ok(()) as Result<(), std::io::Error> //! Ok(()) as Result<(), Error>
//! })), //! })),
//! ); //! );
//! //!

View file

@ -130,7 +130,8 @@ where
Box::pin(async move { Box::pin(async move {
let uploaded = match handle_multipart(multipart, form.clone()).await { let uploaded = match handle_multipart(multipart, form.clone()).await {
Ok(uploaded) => uploaded, Ok(Ok(uploaded)) => uploaded,
Ok(Err(e)) => return Err(e.into()),
Err(e) => { Err(e) => {
if let Some(f) = form.transform_error.clone() { if let Some(f) = form.transform_error.clone() {
return Err((f)(e)); return Err((f)(e));

View file

@ -157,8 +157,8 @@ pub type FileFn<T, E> = Arc<
dyn Fn( dyn Fn(
String, String,
Mime, Mime,
Pin<Box<dyn Stream<Item = Result<Bytes, Error<E>>>>>, Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>,
) -> Pin<Box<dyn Future<Output = Result<T, Error<E>>>>> ) -> Pin<Box<dyn Future<Output = Result<T, E>>>>
+ Send + Send
+ Sync, + Sync,
>; >;
@ -211,7 +211,7 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// # use tokio::sync::mpsc::channel; /// # use tokio::sync::mpsc::channel;
/// # use futures_util::stream::StreamExt; /// # use futures_util::stream::StreamExt;
/// # /// #
@ -226,13 +226,13 @@ impl<T, E> Field<T, E> {
/// } /// }
/// } /// }
/// } /// }
/// Ok(()) as Result<_, std::io::Error> /// Ok(()) as Result<_, Error>
/// } /// }
/// })); /// }));
/// ``` /// ```
pub fn file<F, Fut>(f: F) -> Self pub fn file<F, Fut>(f: F) -> Self
where where
F: Fn(String, Mime, Pin<Box<dyn Stream<Item = Result<Bytes, Error<E>>>>>) -> Fut F: Fn(String, Mime, Pin<Box<dyn Stream<Item = Result<Bytes, Error>>>>) -> Fut
+ Send + Send
+ Sync + Sync
+ Clone + Clone
@ -242,7 +242,7 @@ impl<T, E> Field<T, E> {
{ {
Field::File(Arc::new(move |filename, mime, stream| { Field::File(Arc::new(move |filename, mime, stream| {
let f = f.clone(); let f = f.clone();
Box::pin(async move { (f)(filename, mime, stream).await.map_err(Error::FileFn) }) Box::pin(async move { (f)(filename, mime, stream).await })
})) }))
} }
@ -250,8 +250,8 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// let form = Form::<(), std::io::Error>::new().field("text-field", Field::bytes()); /// let form = Form::<(), Error>::new().field("text-field", Field::bytes());
pub fn bytes() -> Self { pub fn bytes() -> Self {
Field::Bytes Field::Bytes
} }
@ -260,8 +260,8 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// let form = Form::<(), std::io::Error>::new().field("text-field", Field::text()); /// let form = Form::<(), Error>::new().field("text-field", Field::text());
pub fn text() -> Self { pub fn text() -> Self {
Field::Text Field::Text
} }
@ -270,8 +270,8 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// let form = Form::<(), std::io::Error>::new().field("int-field", Field::int()); /// let form = Form::<(), Error>::new().field("int-field", Field::int());
/// ``` /// ```
pub fn int() -> Self { pub fn int() -> Self {
Field::Int Field::Int
@ -281,8 +281,8 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// let form = Form::<(), std::io::Error>::new().field("float-field", Field::float()); /// let form = Form::<(), Error>::new().field("float-field", Field::float());
/// ``` /// ```
pub fn float() -> Self { pub fn float() -> Self {
Field::Float Field::Float
@ -292,9 +292,9 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// # fn main() { /// # fn main() {
/// let form = Form::<(), std::io::Error>::new() /// let form = Form::<(), Error>::new()
/// .field( /// .field(
/// "array-field", /// "array-field",
/// Field::array(Field::text()) /// Field::array(Field::text())
@ -309,9 +309,9 @@ impl<T, E> Field<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// # fn main() { /// # fn main() {
/// let form = Form::<(), std::io::Error>::new() /// let form = Form::<(), Error>::new()
/// .field( /// .field(
/// "map-field", /// "map-field",
/// Field::map() /// Field::map()
@ -434,9 +434,9 @@ impl<T, E> Map<T, E> {
/// Add a `Field` to a map /// Add a `Field` to a map
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::Field; /// # use actix_form_data::{Error, Field};
/// # /// #
/// Field::<(), std::io::Error>::map() /// Field::<(), Error>::map()
/// .field("sub-field", Field::text()) /// .field("sub-field", Field::text())
/// .field("sub-field-two", Field::text()) /// .field("sub-field-two", Field::text())
/// .finalize(); /// .finalize();
@ -449,9 +449,9 @@ impl<T, E> Map<T, E> {
/// Finalize the map into a `Field`, so it can be added to a Form /// Finalize the map into a `Field`, so it can be added to a Form
/// ```rust /// ```rust
/// # use actix_form_data::Field; /// # use actix_form_data::{Error, Field};
/// # /// #
/// Field::<(), std::io::Error>::map() /// Field::<(), Error>::map()
/// .field("sub-field", Field::text()) /// .field("sub-field", Field::text())
/// .field("sub-field-two", Field::text()) /// .field("sub-field-two", Field::text())
/// .finalize(); /// .finalize();
@ -477,8 +477,8 @@ impl<T, E> Map<T, E> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use actix_form_data::{Form, Field}; /// # use actix_form_data::{Error, Form, Field};
/// let form = Form::<(), std::io::Error>::new() /// let form = Form::<(), Error>::new()
/// .field("field-name", Field::text()) /// .field("field-name", Field::text())
/// .field("second-field", Field::int()) /// .field("second-field", Field::int())
/// .field("third-field", Field::float()) /// .field("third-field", Field::float())
@ -502,7 +502,7 @@ pub struct Form<T, E> {
pub(crate) max_field_size: usize, pub(crate) max_field_size: usize,
pub(crate) max_files: u32, pub(crate) max_files: u32,
pub(crate) max_file_size: usize, pub(crate) max_file_size: usize,
pub(crate) transform_error: Option<Arc<dyn Fn(Error<E>) -> actix_web::Error + Send + Sync>>, pub(crate) transform_error: Option<Arc<dyn Fn(Error) -> actix_web::Error + Send + Sync>>,
inner: Map<T, E>, inner: Map<T, E>,
} }
@ -549,7 +549,7 @@ impl<T, E> Form<T, E> {
/// Set the Transform Error method to convert Error types into actix_web::Error by hand /// Set the Transform Error method to convert Error types into actix_web::Error by hand
pub fn transform_error( pub fn transform_error(
mut self, mut self,
f: impl Fn(Error<E>) -> actix_web::Error + Send + Sync + 'static, f: impl Fn(Error) -> actix_web::Error + Send + Sync + 'static,
) -> Self { ) -> Self {
self.transform_error = Some(Arc::new(f)); self.transform_error = Some(Arc::new(f));
self self

View file

@ -65,7 +65,7 @@ fn consolidate<T>(mf: MultipartForm<T>) -> Value<T> {
) )
} }
fn parse_multipart_name<E>(name: String) -> Result<Vec<NamePart>, Error<E>> { fn parse_multipart_name(name: String) -> Result<Vec<NamePart>, Error> {
name.split('[') name.split('[')
.map(|part| { .map(|part| {
if part.len() == 1 && part.ends_with(']') { if part.len() == 1 && part.ends_with(']') {
@ -104,7 +104,7 @@ async fn handle_file_upload<T, E>(
filename: Option<String>, filename: Option<String>,
form: Form<T, E>, form: Form<T, E>,
file_fn: FileFn<T, E>, file_fn: FileFn<T, E>,
) -> Result<MultipartContent<T>, Error<E>> ) -> Result<Result<MultipartContent<T>, E>, Error>
where where
T: 'static, T: 'static,
E: 'static, E: 'static,
@ -142,20 +142,23 @@ where
} }
})), })),
) )
.await?; .await;
Ok(MultipartContent::File(FileMeta { match result {
filename, Ok(result) => Ok(Ok(MultipartContent::File(FileMeta {
content_type, filename,
result, content_type,
})) result,
}))),
Err(e) => Ok(Err(e)),
}
} }
async fn handle_form_data<T, E>( async fn handle_form_data<T, E>(
mut field: actix_multipart::Field, mut field: actix_multipart::Field,
term: FieldTerminator<T, E>, term: FieldTerminator<T, E>,
form: Form<T, E>, form: Form<T, E>,
) -> Result<MultipartContent<T>, Error<E>> ) -> Result<MultipartContent<T>, Error>
where where
T: 'static, T: 'static,
E: 'static, E: 'static,
@ -195,7 +198,7 @@ where
async fn handle_stream_field<T, E>( async fn handle_stream_field<T, E>(
field: actix_multipart::Field, field: actix_multipart::Field,
form: Form<T, E>, form: Form<T, E>,
) -> Result<MultipartHash<T>, Error<E>> ) -> Result<Result<MultipartHash<T>, E>, Error>
where where
T: 'static, T: 'static,
E: 'static, E: 'static,
@ -211,19 +214,22 @@ where
let content = match term { let content = match term {
FieldTerminator::File(file_fn) => { FieldTerminator::File(file_fn) => {
handle_file_upload(field, content_disposition.filename, form, file_fn).await? match handle_file_upload(field, content_disposition.filename, form, file_fn).await? {
Ok(content) => content,
Err(e) => return Ok(Err(e)),
}
} }
term => handle_form_data(field, term, form.clone()).await?, term => handle_form_data(field, term, form.clone()).await?,
}; };
Ok((name, content)) Ok(Ok((name, content)))
} }
/// Handle multipart streams from Actix Web /// Handle multipart streams from Actix Web
pub async fn handle_multipart<T, E>( pub async fn handle_multipart<T, E>(
m: actix_multipart::Multipart, m: actix_multipart::Multipart,
form: Form<T, E>, form: Form<T, E>,
) -> Result<Value<T>, Error<E>> ) -> Result<Result<Value<T>, E>, Error>
where where
T: 'static, T: 'static,
E: 'static, E: 'static,
@ -245,7 +251,10 @@ where
} }
opt = unordered.next() => { opt = unordered.next() => {
if let Some(res) = opt { if let Some(res) = opt {
let (name_parts, content) = res?; let (name_parts, content) = match res? {
Ok(tup) => tup,
Err(e) => return Ok(Err(e)),
};
let (l, r) = count(&content, file_count, field_count, &form)?; let (l, r) = count(&content, file_count, field_count, &form)?;
file_count = l; file_count = l;
@ -258,7 +267,7 @@ where
} }
} }
Ok(consolidate(multipart_form)) Ok(Ok(consolidate(multipart_form)))
} }
fn count<T, E>( fn count<T, E>(
@ -266,7 +275,7 @@ fn count<T, E>(
mut file_count: u32, mut file_count: u32,
mut field_count: u32, mut field_count: u32,
form: &Form<T, E>, form: &Form<T, E>,
) -> Result<(u32, u32), Error<E>> { ) -> Result<(u32, u32), Error> {
match content { match content {
MultipartContent::File(_) => { MultipartContent::File(_) => {
file_count += 1; file_count += 1;