From aa9fa0f4574f8bad7a8f4259c97af08c33fd4936 Mon Sep 17 00:00:00 2001 From: Dominic Date: Tue, 5 May 2020 19:31:02 +0200 Subject: [PATCH] doc & ui-test for FromBody --- gotham_restful/Cargo.toml | 1 + gotham_restful/src/types.rs | 34 +++++++++++++++---- gotham_restful/tests/ui.rs | 10 ++++++ gotham_restful/tests/ui/from_body_enum.rs | 12 +++++++ gotham_restful/tests/ui/from_body_enum.stderr | 5 +++ gotham_restful_derive/src/from_body.rs | 20 +++++------ 6 files changed, 66 insertions(+), 16 deletions(-) create mode 100644 gotham_restful/tests/ui.rs create mode 100644 gotham_restful/tests/ui/from_body_enum.rs create mode 100644 gotham_restful/tests/ui/from_body_enum.stderr diff --git a/gotham_restful/Cargo.toml b/gotham_restful/Cargo.toml index 836cd19..a571a2d 100644 --- a/gotham_restful/Cargo.toml +++ b/gotham_restful/Cargo.toml @@ -39,6 +39,7 @@ uuid = { version = "0.8.1", optional = true } diesel = { version = "1.4.4", features = ["postgres"] } futures-executor = "0.3.4" paste = "0.1.12" +trybuild = "1.0.26" [features] default = ["errorlog"] diff --git a/gotham_restful/src/types.rs b/gotham_restful/src/types.rs index 504cf94..6c3d635 100644 --- a/gotham_restful/src/types.rs +++ b/gotham_restful/src/types.rs @@ -43,13 +43,36 @@ impl ResponseBody for T } -/// This trait must be implemented by every type that can be used as a request body. It allows -/// to create the type from a hyper body chunk and it's content type. +/** +This trait should be implemented for every type that can be built from an HTTP request body +plus its media type. For most use cases it is sufficient to derive this trait, you usually +don't need to manually implement this. Therefore, make sure that the first variable of +your struct can be built from [`Bytes`], and the second one can be build from [`Mime`]. +If you have any additional variables, they need to be `Default`. This is an example of +such a struct: + +```rust +# #[macro_use] extern crate gotham_restful; +# use gotham_restful::*; +#[derive(FromBody, RequestBody)] +#[supported_types(mime::IMAGE_GIF, mime::IMAGE_JPEG, mime::IMAGE_PNG)] +struct RawImage { + content: Vec, + content_type: Mime +} +``` + + [`Bytes`]: ../bytes/struct.Bytes.html + [`Mime`]: ../mime/struct.Mime.html +*/ pub trait FromBody : Sized { + /// The error type returned by the conversion if it was unsuccessfull. When using the derive + /// macro, there is no way to trigger an error, so + /// [`FromBodyNoError`](struct.FromBodyNoError.html) is used here. type Err : Error; - /// Create the request body from a raw body and the content type. + /// Perform the conversion. fn from_body(body : Bytes, content_type : Mime) -> Result; } @@ -63,9 +86,8 @@ impl FromBody for T } } -/// This error type can be used by `FromBody` implementations when there is no need to return any -/// errors. - +/// This error type can be used by [`FromBody`](trait.FromBody.html) implementations when there +/// is no need to return any errors. #[derive(Clone, Copy, Debug, Error)] #[error("No Error")] pub struct FromBodyNoError; diff --git a/gotham_restful/tests/ui.rs b/gotham_restful/tests/ui.rs new file mode 100644 index 0000000..04e6311 --- /dev/null +++ b/gotham_restful/tests/ui.rs @@ -0,0 +1,10 @@ +use trybuild::TestCases; + +#[test] +fn ui() +{ + let t = TestCases::new(); + + // always enabled + t.compile_fail("tests/ui/from_body_enum.rs"); +} \ No newline at end of file diff --git a/gotham_restful/tests/ui/from_body_enum.rs b/gotham_restful/tests/ui/from_body_enum.rs new file mode 100644 index 0000000..24eb9db --- /dev/null +++ b/gotham_restful/tests/ui/from_body_enum.rs @@ -0,0 +1,12 @@ +#[macro_use] extern crate gotham_restful; + +#[derive(FromBody)] +enum FromBodyEnum +{ + SomeVariant(Vec), + OtherVariant(String) +} + +fn main() +{ +} diff --git a/gotham_restful/tests/ui/from_body_enum.stderr b/gotham_restful/tests/ui/from_body_enum.stderr new file mode 100644 index 0000000..26cab8b --- /dev/null +++ b/gotham_restful/tests/ui/from_body_enum.stderr @@ -0,0 +1,5 @@ +error: #[derive(FromBody)] only works for structs + --> $DIR/from_body_enum.rs:4:1 + | +4 | enum FromBodyEnum + | ^^^^ diff --git a/gotham_restful_derive/src/from_body.rs b/gotham_restful_derive/src/from_body.rs index e57c14c..6d48201 100644 --- a/gotham_restful_derive/src/from_body.rs +++ b/gotham_restful_derive/src/from_body.rs @@ -21,25 +21,25 @@ struct ParsedFields impl ParsedFields { - fn from_named(fields : I) -> Result + fn from_named(fields : I) -> Self where I : Iterator { let fields = fields.map(|field| (field.ident.unwrap(), field.ty)).collect(); - Ok(Self { fields, named: true }) + Self { fields, named: true } } - fn from_unnamed(fields : I) -> Result + fn from_unnamed(fields : I) -> Self where I : Iterator { let fields = fields.enumerate().map(|(i, field)| (format_ident!("arg{}", i), field.ty)).collect(); - Ok(Self { fields, named: false }) + Self { fields, named: false } } - fn from_unit() -> Result + fn from_unit() -> Self { - Ok(Self { fields: Vec::new(), named: false }) + Self { fields: Vec::new(), named: false } } } @@ -53,12 +53,12 @@ pub fn expand_from_body(input : DeriveInput) -> Result Data::Enum(inum) => Err(inum.enum_token.span()), Data::Struct(strukt) => Ok(strukt), Data::Union(uni) => Err(uni.union_token.span()) - }.map_err(|span| Error::new(span, "#[derive(FromBody)] only works for enums"))?; + }.map_err(|span| Error::new(span, "#[derive(FromBody)] only works for structs"))?; let fields = match strukt.fields { - Fields::Named(named) => ParsedFields::from_named(named.named.into_iter())?, - Fields::Unnamed(unnamed) => ParsedFields::from_unnamed(unnamed.unnamed.into_iter())?, - Fields::Unit => ParsedFields::from_unit()? + Fields::Named(named) => ParsedFields::from_named(named.named.into_iter()), + Fields::Unnamed(unnamed) => ParsedFields::from_unnamed(unnamed.unnamed.into_iter()), + Fields::Unit => ParsedFields::from_unit() }; let mut where_clause = quote!();