2016-10-19 07:30:02 +00:00
|
|
|
//! Success, failure, and forward handling.
|
|
|
|
//!
|
|
|
|
//! The `Outcome<S, E, F>` type is similar to the standard library's `Result<S,
|
|
|
|
//! E>` type. It is an enum with three variants, each containing a value:
|
|
|
|
//! `Success(S)`, which represents a successful outcome, `Failure(E)`, which
|
|
|
|
//! represents a failing outcome, and `Forward(F)`, which represents neither a
|
|
|
|
//! success or failure, but instead, indicates that processing could not be
|
|
|
|
//! handled and should instead be _forwarded_ to whatever can handle the
|
|
|
|
//! processing next.
|
|
|
|
//!
|
|
|
|
//! The `Outcome` type is the return type of many of the core Rocket traits,
|
|
|
|
//! including [FromRequest](../request/trait.FromRequest.html),
|
|
|
|
//! [FromData](../request/trait.FromData.html), and
|
|
|
|
//! [Responder](../response/trait.Responder.html). It is also the return type of
|
|
|
|
//! request handlers via the [Response](../response/type.Response.html) type
|
|
|
|
//! alias.
|
|
|
|
//!
|
|
|
|
//! # Success
|
|
|
|
//!
|
|
|
|
//! A successful `Outcome<S, E, F>`, `Success(S)`, is returned from functions
|
|
|
|
//! that complete successfully. The meaning of a `Success` outcome depends on
|
|
|
|
//! the context. For instance, the `Outcome` of the `from_data` method of the
|
|
|
|
//! `FromData` trait will be matched against the type expected by the user. For
|
|
|
|
//! example, consider the following handler:
|
|
|
|
//!
|
|
|
|
//! ```rust,ignore
|
|
|
|
//! #[post("/", data = "<my_val>")]
|
|
|
|
//! fn hello(my_val: S) -> ... { }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! The `FromData` implementation for the type `S` returns an `Outcome` with a
|
|
|
|
//! `Success(S)`. If `from_data` returns a `Success`, the `Success` value will
|
|
|
|
//! be unwrapped and the value will be used as the value of `my_val`.
|
|
|
|
//!
|
|
|
|
//! # Failure
|
|
|
|
//!
|
|
|
|
//! A failure `Outcome<S, E, F>`, `Failure(E)`, is returned when a function
|
|
|
|
//! fails with some error and no processing can or should continue as a result.
|
|
|
|
//! The meaning of a failure depends on the context.
|
|
|
|
//!
|
|
|
|
//! It Rocket, a `Failure` generally means that a request is taken out of normal
|
|
|
|
//! processing. The request is then given to the catcher corresponding to some
|
|
|
|
//! status code. users can catch failures by requesting a type of `Result<S, E>`
|
|
|
|
//! or `Option<S>` in request handlers. For example, if a user's handler looks
|
|
|
|
//! like:
|
|
|
|
//!
|
|
|
|
//! ```rust,ignore
|
|
|
|
//! #[post("/", data = "<my_val>")]
|
|
|
|
//! fn hello(my_val: Result<S, E>) -> ... { }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! The `FromData` implementation for the type `S` returns an `Outcome` with a
|
|
|
|
//! `Success(S)` and `Failure(E)`. If `from_data` returns a `Failure`, the
|
|
|
|
//! `Failure` value will be unwrapped and the value will be used as the `Err`
|
|
|
|
//! value of `my_val` while a `Success` will be unwrapped and used the `Ok`
|
|
|
|
//! value.
|
|
|
|
//!
|
|
|
|
//! # Forward
|
|
|
|
//!
|
|
|
|
//! A forward `Outcome<S, E, F>`, `Forward(F)`, is returned when a function
|
|
|
|
//! wants to indicate that the requested processing should be _forwarded_ to the
|
|
|
|
//! next available processor. Again, the exact meaning depends on the context.
|
|
|
|
//!
|
|
|
|
//! In Rocket, a `Forward` generally means that a request is forwarded to the
|
|
|
|
//! next available request handler. For example, consider the following request
|
|
|
|
//! handler:
|
|
|
|
//!
|
|
|
|
//! ```rust,ignore
|
|
|
|
//! #[post("/", data = "<my_val>")]
|
|
|
|
//! fn hello(my_val: S) -> ... { }
|
|
|
|
//! ```
|
|
|
|
//!
|
|
|
|
//! The `FromData` implementation for the type `S` returns an `Outcome` with a
|
|
|
|
//! `Success(S)`, `Failure(E)`, and `Forward(F)`. If the `Outcome` is a
|
|
|
|
//! `Forward`, the `hello` handler isn't called. Instead, the incoming request
|
|
|
|
//! is forwarded, or passed on to, the next matching route, if any. Ultimately,
|
|
|
|
//! if there are no non-forwarding routes, forwarded requests are handled by the
|
|
|
|
//! 404 catcher. Similar to `Failure`s, users can catch `Forward`s by requesting
|
|
|
|
//! a type of `Option<S>`. If an `Outcome` is a `Forward`, the `Option` will be
|
|
|
|
//! `None`.
|
|
|
|
|
2016-10-04 00:09:13 +00:00
|
|
|
use std::fmt;
|
2016-04-11 10:57:23 +00:00
|
|
|
|
|
|
|
use term_painter::Color::*;
|
2016-10-14 01:39:23 +00:00
|
|
|
use term_painter::Color;
|
2016-04-11 10:57:23 +00:00
|
|
|
use term_painter::ToStyle;
|
2016-10-04 00:09:13 +00:00
|
|
|
|
2016-10-19 07:30:02 +00:00
|
|
|
/// An enum representing success (`Success`), failure (`Failure`), or
|
|
|
|
/// forwarding (`Forward`).
|
2016-10-08 06:20:49 +00:00
|
|
|
#[must_use]
|
2016-10-19 07:30:02 +00:00
|
|
|
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
2016-10-14 01:39:23 +00:00
|
|
|
pub enum Outcome<S, E, F> {
|
|
|
|
/// Contains the success value.
|
|
|
|
Success(S),
|
|
|
|
/// Contains the failure error value.
|
|
|
|
Failure(E),
|
|
|
|
/// Contains the value to forward on.
|
|
|
|
Forward(F),
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
impl<S, E, F> Outcome<S, E, F> {
|
|
|
|
/// Unwraps the Outcome, yielding the contents of a Success.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
2016-10-19 07:30:02 +00:00
|
|
|
/// Panics if the value is not `Success`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.unwrap(), 10);
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn unwrap(self) -> S {
|
|
|
|
match self {
|
|
|
|
Outcome::Success(val) => val,
|
|
|
|
_ => panic!("Expected a successful outcome!")
|
2016-10-09 11:29:02 +00:00
|
|
|
}
|
2016-10-14 01:39:23 +00:00
|
|
|
}
|
2016-10-09 11:29:02 +00:00
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
/// Return true if this `Outcome` is a `Success`.
|
2016-10-19 07:30:02 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.is_success(), true);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.is_success(), false);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Forward(25);
|
|
|
|
/// assert_eq!(x.is_success(), false);
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn is_success(&self) -> bool {
|
|
|
|
match *self {
|
|
|
|
Outcome::Success(_) => true,
|
|
|
|
_ => false
|
|
|
|
}
|
2016-10-09 11:29:02 +00:00
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
/// Return true if this `Outcome` is a `Failure`.
|
2016-10-19 07:30:02 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.is_failure(), false);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.is_failure(), true);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Forward(25);
|
|
|
|
/// assert_eq!(x.is_failure(), false);
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn is_failure(&self) -> bool {
|
2016-04-23 02:48:03 +00:00
|
|
|
match *self {
|
2016-10-14 01:39:23 +00:00
|
|
|
Outcome::Failure(_) => true,
|
|
|
|
_ => false
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
/// Return true if this `Outcome` is a `Forward`.
|
2016-10-19 07:30:02 +00:00
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.is_forward(), false);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.is_forward(), false);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Forward(25);
|
|
|
|
/// assert_eq!(x.is_forward(), true);
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn is_forward(&self) -> bool {
|
2016-04-23 02:48:03 +00:00
|
|
|
match *self {
|
2016-10-14 01:39:23 +00:00
|
|
|
Outcome::Forward(_) => true,
|
|
|
|
_ => false
|
2016-10-08 06:20:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
/// Converts from `Outcome<S, E, F>` to `Option<S>`.
|
|
|
|
///
|
|
|
|
/// Returns the `Some` of the `Success` if this is a `Success`, otherwise
|
|
|
|
/// returns `None`. `self` is consumed, and all other values are discarded.
|
2016-10-19 07:30:02 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.succeeded(), Some(10));
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.succeeded(), None);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Forward(25);
|
|
|
|
/// assert_eq!(x.succeeded(), None);
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn succeeded(self) -> Option<S> {
|
|
|
|
match self {
|
|
|
|
Outcome::Success(val) => Some(val),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts from `Outcome<S, E, F>` to `Option<E>`.
|
|
|
|
///
|
|
|
|
/// Returns the `Some` of the `Failure` if this is a `Failure`, otherwise
|
|
|
|
/// returns `None`. `self` is consumed, and all other values are discarded.
|
2016-10-19 07:30:02 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.failed(), None);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.failed(), Some("Hi! I'm an error."));
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Forward(25);
|
|
|
|
/// assert_eq!(x.failed(), None);
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn failed(self) -> Option<E> {
|
|
|
|
match self {
|
|
|
|
Outcome::Failure(val) => Some(val),
|
|
|
|
_ => None
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
/// Converts from `Outcome<S, E, F>` to `Option<F>`.
|
|
|
|
///
|
|
|
|
/// Returns the `Some` of the `Forward` if this is a `Forward`, otherwise
|
|
|
|
/// returns `None`. `self` is consumed, and all other values are discarded.
|
2016-10-19 07:30:02 +00:00
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.forwarded(), None);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.forwarded(), None);
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Forward(25);
|
|
|
|
/// assert_eq!(x.forwarded(), Some(25));
|
|
|
|
/// ```
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
pub fn forwarded(self) -> Option<F> {
|
|
|
|
match self {
|
|
|
|
Outcome::Forward(val) => Some(val),
|
|
|
|
_ => None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-19 07:30:02 +00:00
|
|
|
/// Converts from `Outcome<S, E, F>` to `Outcome<&S, &E, &F>`.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// assert_eq!(x.as_ref(), Success(&10));
|
|
|
|
///
|
|
|
|
/// let x: Outcome<i32, &str, usize> = Failure("Hi! I'm an error.");
|
|
|
|
/// assert_eq!(x.as_ref(), Failure(&"Hi! I'm an error."));
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn as_ref(&self) -> Outcome<&S, &E, &F> {
|
|
|
|
match *self {
|
|
|
|
Outcome::Success(ref val) => Outcome::Success(val),
|
|
|
|
Outcome::Failure(ref val) => Outcome::Failure(val),
|
|
|
|
Outcome::Forward(ref val) => Outcome::Forward(val),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Converts from `Outcome<S, E, F>` to `Outcome<&mut S, &mut E, &mut F>`.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// # use rocket::outcome::Outcome;
|
|
|
|
/// # use rocket::outcome::Outcome::*;
|
|
|
|
/// #
|
|
|
|
/// let mut x: Outcome<i32, &str, usize> = Success(10);
|
|
|
|
/// if let Success(val) = x.as_mut() {
|
|
|
|
/// *val = 20;
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// assert_eq!(x.unwrap(), 20);
|
|
|
|
/// ```
|
|
|
|
#[inline(always)]
|
|
|
|
pub fn as_mut(&mut self) -> Outcome<&mut S, &mut E, &mut F> {
|
|
|
|
match *self {
|
|
|
|
Outcome::Success(ref mut val) => Outcome::Success(val),
|
|
|
|
Outcome::Failure(ref mut val) => Outcome::Failure(val),
|
|
|
|
Outcome::Forward(ref mut val) => Outcome::Forward(val),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
#[inline(always)]
|
|
|
|
fn formatting(&self) -> (Color, &'static str) {
|
|
|
|
match *self {
|
|
|
|
Outcome::Success(..) => (Green, "Succcess"),
|
|
|
|
Outcome::Failure(..) => (Red, "Failure"),
|
|
|
|
Outcome::Forward(..) => (Yellow, "Forward"),
|
|
|
|
}
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
impl<S, E, F> fmt::Debug for Outcome<S, E, F> {
|
2016-04-11 10:57:23 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2016-10-14 01:39:23 +00:00
|
|
|
write!(f, "Outcome::{}", self.formatting().1)
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-14 01:39:23 +00:00
|
|
|
impl<S, E, F> fmt::Display for Outcome<S, E, F> {
|
2016-04-11 10:57:23 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2016-10-14 01:39:23 +00:00
|
|
|
let (color, string) = self.formatting();
|
|
|
|
write!(f, "{}", color.paint(string))
|
2016-04-11 10:57:23 +00:00
|
|
|
}
|
|
|
|
}
|