Remove use of the 'try_trait' feature.

Add the 'try_outcome' macro to replace uses of '?' on 'Outcome'.
This commit is contained in:
Jacob Pratt 2019-09-10 21:04:34 -04:00 committed by Sergio Benitez
parent b95b6765e1
commit e3c1a4ad3a
11 changed files with 89 additions and 45 deletions

View File

@ -145,7 +145,7 @@ pub fn database_attr(attr: TokenStream, input: TokenStream) -> Result<TokenStrea
fn from_request(request: &'a #request::Request<'r>) -> #request::Outcome<Self, ()> { fn from_request(request: &'a #request::Request<'r>) -> #request::Outcome<Self, ()> {
use ::rocket::{Outcome, http::Status}; use ::rocket::{Outcome, http::Status};
let pool = request.guard::<::rocket::State<#pool_type>>()?; let pool = ::rocket::try_outcome!(request.guard::<::rocket::State<#pool_type>>());
match pool.0.get() { match pool.0.get() {
Ok(conn) => Outcome::Success(#guard_type(conn)), Ok(conn) => Outcome::Success(#guard_type(conn)),

View File

@ -143,7 +143,7 @@ impl<'a, T: Deserialize<'a>> FromData<'a> for Json<T> {
} }
fn from_data(_: &Request<'_>, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> { fn from_data(_: &Request<'_>, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
let string = o.borrowed()?; let string = try_outcome!(o.borrowed());
match serde_json::from_str(&string) { match serde_json::from_str(&string) {
Ok(v) => Success(Json(v)), Ok(v) => Success(Json(v)),
Err(e) => { Err(e) => {

View File

@ -131,7 +131,7 @@ impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> {
fn from_data(_: &Request<'_>, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> { fn from_data(_: &Request<'_>, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
use self::Error::*; use self::Error::*;
let buf = o.borrowed()?; let buf = try_outcome!(o.borrowed());
match rmp_serde::from_slice(&buf) { match rmp_serde::from_slice(&buf) {
Ok(val) => Success(MsgPack(val)), Ok(val) => Success(MsgPack(val)),
Err(e) => { Err(e) => {

View File

@ -219,7 +219,7 @@ pub type Transformed<'a, T> =
/// // Retrieve a borrow to the now transformed `String` (an &str). This /// // Retrieve a borrow to the now transformed `String` (an &str). This
/// // is only correct because we know we _always_ return a `Borrowed` from /// // is only correct because we know we _always_ return a `Borrowed` from
/// // `transform` above. /// // `transform` above.
/// let string = outcome.borrowed()?; /// let string = try_outcome!(outcome.borrowed());
/// ///
/// // Perform a crude, inefficient parse. /// // Perform a crude, inefficient parse.
/// let splits: Vec<&str> = string.split(" ").collect(); /// let splits: Vec<&str> = string.split(" ").collect();
@ -370,16 +370,17 @@ pub trait FromData<'a>: Sized {
/// following: /// following:
/// ///
/// ```rust /// ```rust
/// # #[macro_use] extern crate rocket;
/// # use rocket::data::{Data, FromData, Transformed, Outcome}; /// # use rocket::data::{Data, FromData, Transformed, Outcome};
/// # fn f<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromData<'a>>::Error> { /// # fn f<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromData<'a>>::Error> {
/// // If `Owned` was returned from `transform`: /// // If `Owned` was returned from `transform`:
/// let data = outcome.owned()?; /// let data = try_outcome!(outcome.owned());
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// ///
/// # fn g<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromData<'a>>::Error> { /// # fn g<'a>(outcome: Transformed<'a, Data>) -> Outcome<Data, <Data as FromData<'a>>::Error> {
/// // If `Borrowed` was returned from `transform`: /// // If `Borrowed` was returned from `transform`:
/// let data = outcome.borrowed()?; /// let data = try_outcome!(outcome.borrowed());
/// # unimplemented!() /// # unimplemented!()
/// # } /// # }
/// ``` /// ```
@ -399,7 +400,7 @@ impl<'f> FromData<'f> for Data {
#[inline(always)] #[inline(always)]
fn from_data(_: &Request<'_>, outcome: Transformed<'f, Self>) -> Outcome<Self, Self::Error> { fn from_data(_: &Request<'_>, outcome: Transformed<'f, Self>) -> Outcome<Self, Self::Error> {
Success(outcome.owned()?) outcome.owned()
} }
} }
@ -517,7 +518,7 @@ impl<'a, T: FromDataSimple> FromData<'a> for T {
#[inline(always)] #[inline(always)]
fn from_data(req: &Request<'_>, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> { fn from_data(req: &Request<'_>, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
T::from_data(req, o.owned()?) T::from_data(req, try_outcome!(o.owned()))
} }
} }

View File

@ -1,4 +1,3 @@
#![feature(try_trait)]
#![feature(proc_macro_hygiene)] #![feature(proc_macro_hygiene)]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
@ -95,16 +94,19 @@
//! [testing chapter of the guide]: https://rocket.rs/v0.5/guide/testing/#testing //! [testing chapter of the guide]: https://rocket.rs/v0.5/guide/testing/#testing
#[allow(unused_imports)] #[macro_use] extern crate rocket_codegen; #[allow(unused_imports)] #[macro_use] extern crate rocket_codegen;
// FIXME(rustdoc): We should be able to doc(inline) and not doc the
// rocket_codegen crate at all. Alas, doc-inlining will currently 1) show hidden
// proc-macros, and 2) result in proc-macros pointing to the wrong docs.
#[doc(hidden)] pub use rocket_codegen::*; #[doc(hidden)] pub use rocket_codegen::*;
#[macro_use] extern crate log; #[macro_use] extern crate log;
#[macro_use] extern crate pear; #[macro_use] extern crate pear;
#[doc(hidden)] #[macro_use] pub mod logger; #[doc(hidden)] #[macro_use] pub mod logger;
#[macro_use] pub mod outcome;
pub mod local; pub mod local;
pub mod request; pub mod request;
pub mod response; pub mod response;
pub mod outcome;
pub mod config; pub mod config;
pub mod data; pub mod data;
pub mod handler; pub mod handler;

View File

@ -79,7 +79,6 @@
//! `None`. //! `None`.
use std::fmt; use std::fmt;
use std::ops::Try;
use yansi::{Paint, Color}; use yansi::{Paint, Color};
@ -601,28 +600,68 @@ impl<S, E, F> Outcome<S, E, F> {
} }
} }
impl<S, E, F> Try for Outcome<S, E, F> { /// Unwraps an [`Outcome`] to its success value, otherwise propagating the
type Ok = S; /// forward or failure.
type Error = Result<F, E>; ///
/// In the case of a `Forward` or `Failure` variant, the inner type is passed to
fn into_result(self) -> Result<Self::Ok, Self::Error> { /// [`From`](std::convert::From), allowing for the conversion between specific
match self { /// and more general types. The resulting forward/error is immediately returned.
Success(val) => Ok(val), ///
Forward(val) => Err(Ok(val)), /// Because of the early return, `try_outcome!` can only be used in methods that
Failure(val) => Err(Err(val)), /// return [`Outcome`].
} ///
} /// ## Example
///
fn from_error(val: Self::Error) -> Self { /// ```rust,no_run
match val { /// # #![feature(proc_macro_hygiene)]
Ok(val) => Forward(val), /// # #[macro_use] extern crate rocket;
Err(val) => Failure(val), /// # use std::sync::atomic::{AtomicUsize, Ordering};
} /// use rocket::request::{self, Request, FromRequest, State};
} /// use rocket::outcome::Outcome::*;
///
fn from_ok(val: Self::Ok) -> Self { /// #[derive(Default)]
Success(val) /// struct Atomics {
} /// uncached: AtomicUsize,
/// cached: AtomicUsize,
/// }
///
/// struct Guard1;
/// struct Guard2;
///
/// impl<'a, 'r> FromRequest<'a, 'r> for Guard1 {
/// type Error = ();
///
/// fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> {
/// // Attempt to fetch the guard, passing through any error or forward.
/// let atomics = try_outcome!(req.guard::<State<'_, Atomics>>());
/// atomics.uncached.fetch_add(1, Ordering::Relaxed);
/// req.local_cache(|| atomics.cached.fetch_add(1, Ordering::Relaxed));
///
/// Success(Guard1)
/// }
/// }
///
/// impl<'a, 'r> FromRequest<'a, 'r> for Guard2 {
/// type Error = ();
///
/// fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> {
/// // Attempt to fetch the guard, passing through any error or forward.
/// let guard1: Guard1 = try_outcome!(req.guard::<Guard1>());
/// Success(Guard2)
/// }
/// }
/// ```
#[macro_export]
macro_rules! try_outcome {
($expr:expr $(,)?) => (match $expr {
$crate::outcome::Outcome::Success(val) => val,
$crate::outcome::Outcome::Failure(e) => {
return $crate::outcome::Outcome::Failure(::std::convert::From::from(e))
},
$crate::outcome::Outcome::Forward(f) => {
return $crate::outcome::Outcome::Forward(::std::convert::From::from(f))
},
});
} }
impl<S, E, F> fmt::Debug for Outcome<S, E, F> { impl<S, E, F> fmt::Debug for Outcome<S, E, F> {

View File

@ -211,7 +211,7 @@ impl<'f, T: FromForm<'f>> FromData<'f> for Form<T> {
} }
fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> Outcome<Self, Self::Error> { fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> Outcome<Self, Self::Error> {
<Form<T>>::from_data(o.borrowed()?, true).map(Form) <Form<T>>::from_data(try_outcome!(o.borrowed()), true).map(Form)
} }
} }

View File

@ -105,7 +105,7 @@ impl<'f, T: FromForm<'f>> FromData<'f> for LenientForm<T> {
} }
fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> Outcome<Self, Self::Error> { fn from_data(_: &Request<'_>, o: Transformed<'f, Self>) -> Outcome<Self, Self::Error> {
<Form<T>>::from_data(o.borrowed()?, false).map(LenientForm) <Form<T>>::from_data(try_outcome!(o.borrowed()), false).map(LenientForm)
} }
} }

View File

@ -245,7 +245,7 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
/// type Error = (); /// type Error = ();
/// ///
/// fn from_request(request: &Request<'_>) -> request::Outcome<User, ()> { /// fn from_request(request: &Request<'_>) -> request::Outcome<User, ()> {
/// let db = request.guard::<Database>()?; /// let db = try_outcome!(request.guard::<Database>());
/// request.cookies() /// request.cookies()
/// .get_private("user_id") /// .get_private("user_id")
/// .and_then(|cookie| cookie.value().parse().ok()) /// .and_then(|cookie| cookie.value().parse().ok())
@ -259,7 +259,7 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
/// ///
/// fn from_request(request: &Request<'_>) -> request::Outcome<Admin, ()> { /// fn from_request(request: &Request<'_>) -> request::Outcome<Admin, ()> {
/// // This will unconditionally query the database! /// // This will unconditionally query the database!
/// let user = request.guard::<User>()?; /// let user = try_outcome!(request.guard::<User>());
/// ///
/// if user.is_admin { /// if user.is_admin {
/// Outcome::Success(Admin { user }) /// Outcome::Success(Admin { user })
@ -326,7 +326,7 @@ impl<S, E> IntoOutcome<S, (Status, E), ()> for Result<S, E> {
/// type Error = std::convert::Infallible; /// type Error = std::convert::Infallible;
/// ///
/// fn from_request(request: &'a Request<'_>) -> request::Outcome<Self, Self::Error> { /// fn from_request(request: &'a Request<'_>) -> request::Outcome<Self, Self::Error> {
/// let user = request.guard::<&User>()?; /// let user = try_outcome!(request.guard::<&User>());
/// ///
/// if user.is_admin { /// if user.is_admin {
/// Outcome::Success(Admin { user }) /// Outcome::Success(Admin { user })

View File

@ -6,7 +6,7 @@ mod tests;
use std::{io, env}; use std::{io, env};
use std::fs::File; use std::fs::File;
use rocket::{Request, Handler, Route, Data, Catcher}; use rocket::{Request, Handler, Route, Data, Catcher, try_outcome};
use rocket::http::{Status, RawStr}; use rocket::http::{Status, RawStr};
use rocket::response::{self, Responder, status::Custom}; use rocket::response::{self, Responder, status::Custom};
use rocket::handler::Outcome; use rocket::handler::Outcome;
@ -30,10 +30,11 @@ fn name<'a>(req: &'a Request, _: Data) -> Outcome<'a> {
} }
fn echo_url<'r>(req: &'r Request, _: Data) -> Outcome<'r> { fn echo_url<'r>(req: &'r Request, _: Data) -> Outcome<'r> {
let param = req.get_param::<&RawStr>(1) let param_outcome = req.get_param::<&RawStr>(1)
.and_then(|res| res.ok()) .and_then(|res| res.ok())
.into_outcome(Status::BadRequest)?; .into_outcome(Status::BadRequest);
let param = try_outcome!(param_outcome);
Outcome::try_from(req, RawStr::from_str(param).url_decode()) Outcome::try_from(req, RawStr::from_str(param).url_decode())
} }
@ -79,10 +80,11 @@ impl CustomHandler {
impl Handler for CustomHandler { impl Handler for CustomHandler {
fn handle<'r>(&self, req: &'r Request, data: Data) -> Outcome<'r> { fn handle<'r>(&self, req: &'r Request, data: Data) -> Outcome<'r> {
let id = req.get_param::<&RawStr>(0) let id_outcome = req.get_param::<&RawStr>(0)
.and_then(|res| res.ok()) .and_then(|res| res.ok())
.or_forward(data)?; .or_forward(data);
let id = try_outcome!(id_outcome);
Outcome::from(req, format!("{} - {}", self.data, id)) Outcome::from(req, format!("{} - {}", self.data, id))
} }
} }

View File

@ -22,7 +22,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Guard1 {
type Error = (); type Error = ();
fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> { fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> {
let atomics = req.guard::<State<'_, Atomics>>()?; let atomics = try_outcome!(req.guard::<State<'_, Atomics>>());
atomics.uncached.fetch_add(1, Ordering::Relaxed); atomics.uncached.fetch_add(1, Ordering::Relaxed);
req.local_cache(|| atomics.cached.fetch_add(1, Ordering::Relaxed)); req.local_cache(|| atomics.cached.fetch_add(1, Ordering::Relaxed));
@ -34,7 +34,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Guard2 {
type Error = (); type Error = ();
fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> { fn from_request(req: &'a Request<'r>) -> request::Outcome<Self, ()> {
req.guard::<Guard1>()?; try_outcome!(req.guard::<Guard1>());
Success(Guard2) Success(Guard2)
} }
} }