From 7b48ca710319f40f6f597f09c15588dd72733db7 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Tue, 18 Apr 2017 21:52:02 -0700 Subject: [PATCH] Add optional input for IntoOutcome. Add mapper methods to Outcome. This is a breaking change to `IntoOutcome`. The MsgPack and JSON types now use `into_outcome` to generate the final `Outcome` from their `FromData` implementations. Resolves #98. --- contrib/src/json.rs | 14 +++---- contrib/src/msgpack.rs | 12 ++---- lib/src/data/from_data.rs | 6 ++- lib/src/outcome.rs | 70 ++++++++++++++++++++++++++++++++- lib/src/request/from_request.rs | 7 +++- lib/src/response/flash.rs | 2 +- 6 files changed, 88 insertions(+), 23 deletions(-) diff --git a/contrib/src/json.rs b/contrib/src/json.rs index 437c3022..3c7b412a 100644 --- a/contrib/src/json.rs +++ b/contrib/src/json.rs @@ -2,7 +2,7 @@ use std::ops::{Deref, DerefMut}; use std::io::Read; use rocket::config; -use rocket::outcome::Outcome; +use rocket::outcome::{Outcome, IntoOutcome}; use rocket::request::Request; use rocket::data::{self, Data, FromData}; use rocket::response::{self, Responder, content}; @@ -100,14 +100,10 @@ impl FromData for JSON { .and_then(|c| c.limits.get("json")) .unwrap_or(LIMIT); - let reader = data.open().take(size_limit); - match serde_json::from_reader(reader).map(|val| JSON(val)) { - Ok(value) => Outcome::Success(value), - Err(e) => { - error_!("Couldn't parse JSON body: {:?}", e); - Outcome::Failure((Status::BadRequest, e)) - } - } + serde_json::from_reader(data.open().take(size_limit)) + .map(|val| JSON(val)) + .map_err(|e| { error_!("Couldn't parse JSON body: {:?}", e); e }) + .into_outcome(Status::BadRequest) } } diff --git a/contrib/src/msgpack.rs b/contrib/src/msgpack.rs index ce417bcc..f8a47d1d 100644 --- a/contrib/src/msgpack.rs +++ b/contrib/src/msgpack.rs @@ -4,7 +4,7 @@ use std::ops::{Deref, DerefMut}; use std::io::{Cursor, Read}; use rocket::config; -use rocket::outcome::Outcome; +use rocket::outcome::{Outcome, IntoOutcome}; use rocket::request::Request; use rocket::data::{self, Data, FromData}; use rocket::response::{self, Responder, Response}; @@ -120,13 +120,9 @@ impl FromData for MsgPack { return Outcome::Failure((Status::BadRequest, e)); }; - match rmp_serde::from_slice(&buf).map(|val| MsgPack(val)) { - Ok(value) => Outcome::Success(value), - Err(e) => { - error_!("Couldn't parse MessagePack body: {:?}", e); - Outcome::Failure((Status::BadRequest, e)) - } - } + rmp_serde::from_slice(&buf).map(|val| MsgPack(val)) + .map_err(|e| { error_!("Couldn't parse MessagePack body: {:?}", e); e }) + .into_outcome(Status::BadRequest) } } diff --git a/lib/src/data/from_data.rs b/lib/src/data/from_data.rs index 57ad8203..bd233dcd 100644 --- a/lib/src/data/from_data.rs +++ b/lib/src/data/from_data.rs @@ -10,11 +10,13 @@ use data::Data; pub type Outcome = outcome::Outcome; impl<'a, S, E> IntoOutcome for Result { + type Input = Status; + #[inline] - fn into_outcome(self) -> Outcome { + fn into_outcome(self, status: Status) -> Outcome { match self { Ok(val) => Success(val), - Err(err) => Failure((Status::InternalServerError, err)) + Err(err) => Failure((status, err)) } } } diff --git a/lib/src/outcome.rs b/lib/src/outcome.rs index 2ce8b634..b9dc5415 100644 --- a/lib/src/outcome.rs +++ b/lib/src/outcome.rs @@ -105,7 +105,9 @@ pub enum Outcome { /// Conversion trait from some type into an Outcome type. pub trait IntoOutcome { - fn into_outcome(self) -> Outcome; + type Input: Sized; + + fn into_outcome(self, input: Self::Input) -> Outcome; } impl Outcome { @@ -329,6 +331,72 @@ impl Outcome { } } + /// Maps an `Outcome` to an `Outcome` by applying the + /// function `f` to the value of type `S` in `self` if `self` is an + /// `Outcome::Success`. + /// + /// ```rust + /// # use rocket::outcome::Outcome; + /// # use rocket::outcome::Outcome::*; + /// # + /// let x: Outcome = Success(10); + /// + /// let mapped = x.map(|v| if v == 10 { "10" } else { "not 10" }); + /// assert_eq!(mapped, Success("10")); + /// ``` + #[inline] + pub fn map T>(self, f: M) -> Outcome { + match self { + Success(val) => Success(f(val)), + Failure(val) => Failure(val), + Forward(val) => Forward(val), + } + } + + /// Maps an `Outcome` to an `Outcome` by applying the + /// function `f` to the value of type `E` in `self` if `self` is an + /// `Outcome::Failure`. + /// + /// ```rust + /// # use rocket::outcome::Outcome; + /// # use rocket::outcome::Outcome::*; + /// # + /// let x: Outcome = Failure("hi"); + /// + /// let mapped = x.map_failure(|v| if v == "hi" { 10 } else { 0 }); + /// assert_eq!(mapped, Failure(10)); + /// ``` + #[inline] + pub fn map_failure T>(self, f: M) -> Outcome { + match self { + Success(val) => Success(val), + Failure(val) => Failure(f(val)), + Forward(val) => Forward(val), + } + } + + /// Maps an `Outcome` to an `Outcome` by applying the + /// function `f` to the value of type `F` in `self` if `self` is an + /// `Outcome::Forward`. + /// + /// ```rust + /// # use rocket::outcome::Outcome; + /// # use rocket::outcome::Outcome::*; + /// # + /// let x: Outcome = Forward(5); + /// + /// let mapped = x.map_forward(|v| if v == 5 { "a" } else { "b" }); + /// assert_eq!(mapped, Forward("a")); + /// ``` + #[inline] + pub fn map_forward T>(self, f: M) -> Outcome { + match self { + Success(val) => Success(val), + Failure(val) => Failure(val), + Forward(val) => Forward(f(val)), + } + } + /// Converts from `Outcome` to `Outcome<&mut S, &mut E, &mut F>`. /// /// ```rust diff --git a/lib/src/request/from_request.rs b/lib/src/request/from_request.rs index 0f1dc395..30428974 100644 --- a/lib/src/request/from_request.rs +++ b/lib/src/request/from_request.rs @@ -12,10 +12,13 @@ use http::uri::URI; pub type Outcome = outcome::Outcome; impl IntoOutcome for Result { - fn into_outcome(self) -> Outcome { + type Input = Status; + + #[inline] + fn into_outcome(self, status: Status) -> Outcome { match self { Ok(val) => Success(val), - Err(val) => Failure((Status::BadRequest, val)) + Err(err) => Failure((status, err)) } } } diff --git a/lib/src/response/flash.rs b/lib/src/response/flash.rs index 1fe1cf7f..bde8949a 100644 --- a/lib/src/response/flash.rs +++ b/lib/src/response/flash.rs @@ -242,6 +242,6 @@ impl<'a, 'r> FromRequest<'a, 'r> for Flash<()> { request.cookies().remove(cookie); } - r.into_outcome() + r.into_outcome(Status::BadRequest) } }