From fe59a7fe38a0835bccdeb795fe775862332cc183 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 10 Aug 2018 04:42:30 -0700 Subject: [PATCH] Use better types for 'Error' associated types. --- core/http/src/cookies.rs | 6 +-- core/lib/src/data/from_data.rs | 7 +-- core/lib/src/request/from_request.rs | 55 +++++++++++++----------- core/lib/src/request/param.rs | 2 +- examples/request_guard/src/main.rs | 16 +++---- examples/request_local_state/src/main.rs | 2 +- examples/session/src/main.rs | 6 +-- 7 files changed, 46 insertions(+), 48 deletions(-) diff --git a/core/http/src/cookies.rs b/core/http/src/cookies.rs index db7d36a4..61e87e40 100644 --- a/core/http/src/cookies.rs +++ b/core/http/src/cookies.rs @@ -56,7 +56,7 @@ use Header; /// [private cookie]: /rocket/http/enum.Cookies.html#private-cookies /// /// ```rust -/// # #![feature(plugin, decl_macro)] +/// # #![feature(plugin, decl_macro, never_type)] /// # #![plugin(rocket_codegen)] /// # extern crate rocket; /// # @@ -68,9 +68,9 @@ use Header; /// struct User(usize); /// /// impl<'a, 'r> FromRequest<'a, 'r> for User { -/// type Error = (); +/// type Error = !; /// -/// fn from_request(request: &'a Request<'r>) -> request::Outcome { +/// fn from_request(request: &'a Request<'r>) -> request::Outcome { /// request.cookies() /// .get_private("user_id") /// .and_then(|cookie| cookie.value().parse().ok()) diff --git a/core/lib/src/data/from_data.rs b/core/lib/src/data/from_data.rs index 94e29928..992ceb49 100644 --- a/core/lib/src/data/from_data.rs +++ b/core/lib/src/data/from_data.rs @@ -226,14 +226,15 @@ pub trait FromData: Sized { /// The identity implementation of `FromData`. Always returns `Success`. impl FromData for Data { - type Error = (); + type Error = !; + fn from_data(_: &Request, data: Data) -> Outcome { Success(data) } } impl FromData for Result { - type Error = (); + type Error = !; fn from_data(request: &Request, data: Data) -> Outcome { match T::from_data(request, data) { @@ -245,7 +246,7 @@ impl FromData for Result { } impl FromData for Option { - type Error = (); + type Error = !; fn from_data(request: &Request, data: Data) -> Outcome { match T::from_data(request, data) { diff --git a/core/lib/src/request/from_request.rs b/core/lib/src/request/from_request.rs index 4829fb9b..dc269db7 100644 --- a/core/lib/src/request/from_request.rs +++ b/core/lib/src/request/from_request.rs @@ -181,21 +181,24 @@ impl IntoOutcome for Result { /// key == "valid_api_key" /// } /// +/// #[derive(Debug)] +/// enum ApiKeyError { +/// BadCount, +/// Missing, +/// Invalid, +/// } +/// /// impl<'a, 'r> FromRequest<'a, 'r> for ApiKey { -/// type Error = (); +/// type Error = ApiKeyError; /// -/// fn from_request(request: &'a Request<'r>) -> request::Outcome { +/// fn from_request(request: &'a Request<'r>) -> request::Outcome { /// let keys: Vec<_> = request.headers().get("x-api-key").collect(); -/// if keys.len() != 1 { -/// return Outcome::Failure((Status::BadRequest, ())); +/// match keys.len() { +/// 0 => Outcome::Failure((Status::BadRequest, ApiKeyError::Missing)), +/// 1 if is_valid(keys[0]) => Outcome::Success(ApiKey(keys[0].to_string())), +/// 1 => Outcome::Failure((Status::BadRequest, ApiKeyError::Invalid)), +/// _ => Outcome::Failure((Status::BadRequest, ApiKeyError::BadCount)), /// } -/// -/// let key = keys[0]; -/// if !is_valid(keys[0]) { -/// return Outcome::Forward(()); -/// } -/// -/// return Outcome::Success(ApiKey(key.to_string())); /// } /// } /// @@ -219,7 +222,7 @@ impl IntoOutcome for Result { /// routes (`admin_dashboard` and `user_dashboard`): /// /// ```rust -/// # #![feature(plugin, decl_macro)] +/// # #![feature(plugin, decl_macro, never_type)] /// # #![plugin(rocket_codegen)] /// # extern crate rocket; /// # @@ -282,7 +285,7 @@ impl IntoOutcome for Result { /// used, as illustrated below: /// /// ```rust -/// # #![feature(plugin, decl_macro)] +/// # #![feature(plugin, decl_macro, never_type)] /// # #![plugin(rocket_codegen)] /// # extern crate rocket; /// # @@ -305,9 +308,9 @@ impl IntoOutcome for Result { /// # struct Admin<'a> { user: &'a User }; /// # /// impl<'a, 'r> FromRequest<'a, 'r> for &'a User { -/// type Error = (); +/// type Error = !; /// -/// fn from_request(request: &'a Request<'r>) -> request::Outcome<&'a User, ()> { +/// fn from_request(request: &'a Request<'r>) -> request::Outcome<&'a User, !> { /// // This closure will execute at most once per request, regardless of /// // the number of times the `User` guard is executed. /// let user_result = request.local_cache(|| { @@ -323,9 +326,9 @@ impl IntoOutcome for Result { /// } /// /// impl<'a, 'r> FromRequest<'a, 'r> for Admin<'a> { -/// type Error = (); +/// type Error = !; /// -/// fn from_request(request: &'a Request<'r>) -> request::Outcome, ()> { +/// fn from_request(request: &'a Request<'r>) -> request::Outcome, !> { /// let user = request.guard::<&User>()?; /// /// if user.is_admin { @@ -356,7 +359,7 @@ pub trait FromRequest<'a, 'r>: Sized { } impl<'a, 'r> FromRequest<'a, 'r> for Method { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { Success(request.method()) @@ -364,7 +367,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Method { } impl<'a, 'r> FromRequest<'a, 'r> for &'a Origin<'a> { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { Success(request.uri()) @@ -372,7 +375,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'a Origin<'a> { } impl<'a, 'r> FromRequest<'a, 'r> for &'r Route { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { match request.route() { @@ -383,7 +386,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'r Route { } impl<'a, 'r> FromRequest<'a, 'r> for Cookies<'a> { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { Success(request.cookies()) @@ -391,7 +394,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Cookies<'a> { } impl<'a, 'r> FromRequest<'a, 'r> for &'a Accept { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { match request.accept() { @@ -402,7 +405,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'a Accept { } impl<'a, 'r> FromRequest<'a, 'r> for &'a ContentType { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { match request.content_type() { @@ -413,7 +416,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for &'a ContentType { } impl<'a, 'r> FromRequest<'a, 'r> for SocketAddr { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { match request.remote() { @@ -424,7 +427,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for SocketAddr { } impl<'a, 'r, T: FromRequest<'a, 'r>> FromRequest<'a, 'r> for Result { - type Error = (); + type Error = T::Error; fn from_request(request: &'a Request<'r>) -> Outcome { match T::from_request(request) { @@ -436,7 +439,7 @@ impl<'a, 'r, T: FromRequest<'a, 'r>> FromRequest<'a, 'r> for Result } impl<'a, 'r, T: FromRequest<'a, 'r>> FromRequest<'a, 'r> for Option { - type Error = (); + type Error = !; fn from_request(request: &'a Request<'r>) -> Outcome { match T::from_request(request) { diff --git a/core/lib/src/request/param.rs b/core/lib/src/request/param.rs index f1ff0684..d6c897c1 100644 --- a/core/lib/src/request/param.rs +++ b/core/lib/src/request/param.rs @@ -202,7 +202,7 @@ pub trait FromParam<'a>: Sized { } impl<'a> FromParam<'a> for &'a RawStr { - type Error = (); + type Error = !; #[inline(always)] fn from_param(param: &'a RawStr) -> Result<&'a RawStr, Self::Error> { diff --git a/examples/request_guard/src/main.rs b/examples/request_guard/src/main.rs index 475d2c4e..02bf8e7f 100644 --- a/examples/request_guard/src/main.rs +++ b/examples/request_guard/src/main.rs @@ -1,31 +1,25 @@ -#![feature(plugin, decl_macro)] +#![feature(plugin, decl_macro, never_type)] #![plugin(rocket_codegen)] extern crate rocket; -use std::fmt; use rocket::request::{self, Request, FromRequest}; use rocket::outcome::Outcome::*; #[derive(Debug)] struct HeaderCount(usize); -impl fmt::Display for HeaderCount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) - } -} - impl<'a, 'r> FromRequest<'a, 'r> for HeaderCount { - type Error = (); - fn from_request(request: &'a Request<'r>) -> request::Outcome { + type Error = !; + + fn from_request(request: &'a Request<'r>) -> request::Outcome { Success(HeaderCount(request.headers().len())) } } #[get("/")] fn header_count(header_count: HeaderCount) -> String { - format!("Your request contained {} headers!", header_count) + format!("Your request contained {} headers!", header_count.0) } fn rocket() -> rocket::Rocket { diff --git a/examples/request_local_state/src/main.rs b/examples/request_local_state/src/main.rs index 8d90f2e7..ac12d36a 100644 --- a/examples/request_local_state/src/main.rs +++ b/examples/request_local_state/src/main.rs @@ -1,4 +1,4 @@ -#![feature(plugin, decl_macro)] +#![feature(plugin, decl_macro, never_type)] #![plugin(rocket_codegen)] extern crate rocket; diff --git a/examples/session/src/main.rs b/examples/session/src/main.rs index dfbb279a..5f95424b 100644 --- a/examples/session/src/main.rs +++ b/examples/session/src/main.rs @@ -1,4 +1,4 @@ -#![feature(plugin, decl_macro)] +#![feature(plugin, decl_macro, never_type)] #![plugin(rocket_codegen)] extern crate rocket_contrib; @@ -24,9 +24,9 @@ struct Login { struct User(usize); impl<'a, 'r> FromRequest<'a, 'r> for User { - type Error = (); + type Error = !; - fn from_request(request: &'a Request<'r>) -> request::Outcome { + fn from_request(request: &'a Request<'r>) -> request::Outcome { request.cookies() .get_private("user_id") .and_then(|cookie| cookie.value().parse().ok())