Make Outcome generic on its encapsulated type.

This commit is contained in:
Sergio Benitez 2016-10-07 19:09:05 -07:00
parent d321e1de8d
commit be3530bb44
14 changed files with 65 additions and 51 deletions

View File

@ -4,7 +4,7 @@ extern crate serde_json;
use std::ops::{Deref, DerefMut};
use rocket::request::{Request, FromRequest};
use rocket::response::{Responder, Outcome, data};
use rocket::response::{Responder, Outcome, ResponseOutcome, data};
use rocket::http::hyper::FreshHyperResponse;
use self::serde::{Serialize, Deserialize};
@ -70,7 +70,7 @@ impl<'r, 'c, T: Deserialize> FromRequest<'r, 'c> for JSON<T> {
}
impl<T: Serialize> Responder for JSON<T> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
match serde_json::to_string(&self.0) {
Ok(json_string) => data::JSON(json_string).respond(res),
Err(e) => {

View File

@ -17,7 +17,7 @@ use std::path::{Path, PathBuf};
use std::collections::HashMap;
use rocket::Rocket;
use rocket::response::{Content, Outcome, Responder};
use rocket::response::{Content, Outcome, ResponseOutcome, Responder};
use rocket::http::hyper::FreshHyperResponse;
use rocket::http::ContentType;
@ -133,7 +133,7 @@ impl Template {
}
impl Responder for Template {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
let content_type = match self.1 {
Some(ref ext) => ContentType::from_extension(ext),
None => ContentType::html()

9
lib/src/request/data.rs Normal file
View File

@ -0,0 +1,9 @@
use std::io::Read;
pub struct Data {
stream: Box<Read>
}
pub trait FromData {
fn from_data(data: Data) -> Outcome { }
}

View File

@ -1,4 +1,4 @@
use response::{Responder, Outcome};
use response::{Responder, ResponseOutcome};
use http::hyper::{header, FreshHyperResponse};
use http::mime::{Mime, TopLevel, SubLevel};
use http::ContentType;
@ -6,7 +6,7 @@ use http::ContentType;
pub struct Content<T: Responder>(pub ContentType, pub T);
impl<T: Responder> Responder for Content<T> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> ResponseOutcome<'b> {
res.headers_mut().set(header::ContentType(self.0.clone().into()));
self.1.respond(res)
}
@ -17,7 +17,7 @@ macro_rules! impl_data_type_responder {
pub struct $name<T: Responder>(pub T);
impl<T: Responder> Responder for $name<T> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> ResponseOutcome<'b> {
let mime = Mime(TopLevel::$top, SubLevel::$sub, vec![]);
res.headers_mut().set(header::ContentType(mime));
self.0.respond(res)

View File

@ -1,6 +1,6 @@
use std::io::Write;
use response::{Outcome, Responder};
use response::{ResponseOutcome, Outcome, Responder};
use http::hyper::{header, FreshHyperResponse};
use http::hyper::StatusCode;
@ -13,20 +13,20 @@ impl Empty {
}
impl Responder for Empty {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
res.headers_mut().set(header::ContentLength(0));
*(res.status_mut()) = self.0;
let mut stream = res.start().unwrap();
stream.write_all(b"").unwrap();
Outcome::Complete
Outcome::Success
}
}
pub struct Forward;
impl Responder for Forward {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
Outcome::FailForward(res)
}
}

View File

@ -1,6 +1,6 @@
use std::convert::AsRef;
use response::{Outcome, Responder};
use response::{ResponseOutcome, Responder};
use request::{Request, FromRequest};
use http::hyper::{HyperSetCookie, HyperCookiePair, FreshHyperResponse};
@ -43,7 +43,7 @@ impl<R: Responder> Flash<R> {
}
impl<R: Responder> Responder for Flash<R> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> ResponseOutcome<'b> {
trace_!("Flash: setting message: {}:{}", self.name, self.message);
res.headers_mut().set(HyperSetCookie(vec![self.cookie_pair()]));
self.responder.respond(res)

View File

@ -13,7 +13,7 @@ pub use self::responder::Responder;
pub use self::empty::{Empty, Forward};
pub use self::redirect::Redirect;
pub use self::with_status::StatusResponse;
pub use self::outcome::Outcome;
pub use self::outcome::{Outcome, ResponseOutcome};
pub use self::flash::Flash;
pub use self::named_file::NamedFile;
pub use self::stream::Stream;

View File

@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
use std::io;
use std::ops::{Deref, DerefMut};
use response::{Responder, Outcome};
use response::{Responder, ResponseOutcome};
use http::hyper::{header, FreshHyperResponse};
use http::ContentType;
@ -33,7 +33,7 @@ impl NamedFile {
}
impl Responder for NamedFile {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
if let Some(ext) = self.path().extension() {
let ext_string = ext.to_string_lossy().to_lowercase();
let content_type = ContentType::from_extension(&ext_string);

View File

@ -5,21 +5,26 @@ use term_painter::ToStyle;
use http::hyper::FreshHyperResponse;
pub enum Outcome<'h> {
pub enum Outcome<T> {
/// Signifies a response that completed sucessfully.
Complete,
/// Signifies a response that failed internally.
Bad(FreshHyperResponse<'h>),
/// Signifies a failing response where no further processing should happen.
Success,
/// Signifies a failing response that started responding but fail, so no
/// further processing can occur.
FailStop,
/// Signifies a failing response whose request should be processed further.
FailForward(FreshHyperResponse<'h>),
/// Signifies a response that failed internally without beginning to
/// respond but no further processing should occur.
Bad(T),
/// Signifies a failing response that failed internally without beginning to
/// respond. Further processing should be attempted.
FailForward(T),
}
impl<'h> Outcome<'h> {
pub type ResponseOutcome<'a> = Outcome<FreshHyperResponse<'a>>;
impl<T> Outcome<T> {
pub fn as_str(&self) -> &'static str {
match *self {
Outcome::Complete => "Complete",
Outcome::Success => "Success",
Outcome::FailStop => "FailStop",
Outcome::Bad(..) => "Bad",
Outcome::FailForward(..) => "FailForward",
@ -28,7 +33,7 @@ impl<'h> Outcome<'h> {
fn as_int(&self) -> isize {
match *self {
Outcome::Complete => 0,
Outcome::Success => 0,
Outcome::Bad(..) => 1,
Outcome::FailStop => 2,
Outcome::FailForward(..) => 3,
@ -36,22 +41,22 @@ impl<'h> Outcome<'h> {
}
}
impl<'h> PartialEq for Outcome<'h> {
fn eq(&self, other: &Outcome<'h>) -> bool {
impl<T> PartialEq for Outcome<T> {
fn eq(&self, other: &Outcome<T>) -> bool {
self.as_int() == other.as_int()
}
}
impl<'h> fmt::Debug for Outcome<'h> {
impl<T> fmt::Debug for Outcome<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Outcome::{}", self.as_str())
}
}
impl<'h> fmt::Display for Outcome<'h> {
impl<T> fmt::Display for Outcome<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Outcome::Complete => write!(f, "{}", Green.paint("Complete")),
Outcome::Success => write!(f, "{}", Green.paint("Success")),
Outcome::Bad(..) => write!(f, "{}", Yellow.paint("Bad Completion")),
Outcome::FailStop => write!(f, "{}", Red.paint("Failed")),
Outcome::FailForward(..) => write!(f, "{}", Cyan.paint("Forwarding")),

View File

@ -1,4 +1,4 @@
use response::{Outcome, Responder};
use response::{ResponseOutcome, Outcome, Responder};
use http::hyper::{header, FreshHyperResponse, StatusCode};
#[derive(Debug)]
@ -27,11 +27,11 @@ impl Redirect {
}
impl<'a> Responder for Redirect {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> ResponseOutcome<'b> {
res.headers_mut().set(header::ContentLength(0));
res.headers_mut().set(header::Location(self.1.clone()));
*(res.status_mut()) = self.0;
res.send(b"").unwrap();
Outcome::Complete
Outcome::Success
}
}

View File

@ -2,7 +2,7 @@ use std::io::{Read, Write};
use std::fs::File;
use std::fmt;
use response::Outcome;
use response::{Outcome, ResponseOutcome};
use http::mime::{Mime, TopLevel, SubLevel};
use http::hyper::{header, FreshHyperResponse, StatusCode};
@ -11,29 +11,29 @@ use http::hyper::{header, FreshHyperResponse, StatusCode};
// In particular, we want to try the next ranked route when when parsing
// parameters doesn't work out.
pub trait Responder {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a>;
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> ResponseOutcome<'a>;
}
impl<'a> Responder for &'a str {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> ResponseOutcome<'b> {
if res.headers().get::<header::ContentType>().is_none() {
let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
res.headers_mut().set(header::ContentType(mime));
}
res.send(self.as_bytes()).unwrap();
Outcome::Complete
Outcome::Success
}
}
impl Responder for String {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
if res.headers().get::<header::ContentType>().is_none() {
let mime = Mime(TopLevel::Text, SubLevel::Html, vec![]);
res.headers_mut().set(header::ContentType(mime));
}
res.send(self.as_bytes()).unwrap();
Outcome::Complete
Outcome::Success
}
}
@ -42,7 +42,7 @@ impl Responder for String {
// a way to retrieve a file based on its fd, strangely enough. See...
// https://stackoverflow.com/questions/1188757/getting-filename-from-file-descriptor-in-c
impl Responder for File {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
let size = self.metadata().unwrap().len();
res.headers_mut().set(header::ContentLength(size));
@ -53,12 +53,12 @@ impl Responder for File {
let mut stream = res.start().unwrap();
stream.write_all(&v).unwrap();
Outcome::Complete
Outcome::Success
}
}
impl<T: Responder> Responder for Option<T> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
if self.is_none() {
trace!("Option is none.");
// TODO: Should this be a 404 or 500?
@ -71,7 +71,7 @@ impl<T: Responder> Responder for Option<T> {
impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
// prepend with `default` when using impl specialization
default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
default fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
if self.is_err() {
error_!("{:?}", self.as_ref().err().unwrap());
// TODO: Should this be a 404 or 500?
@ -83,7 +83,7 @@ impl<T: Responder, E: fmt::Debug> Responder for Result<T, E> {
}
impl<T: Responder, E: Responder + fmt::Debug> Responder for Result<T, E> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
match *self {
Ok(ref mut responder) => responder.respond(res),
Err(ref mut responder) => responder.respond(res),

View File

@ -1,6 +1,6 @@
use std::io::{Read, Write, ErrorKind};
use response::{Responder, Outcome};
use response::{Responder, Outcome, ResponseOutcome};
use http::hyper::FreshHyperResponse;
// TODO: Support custom chunk sizes.
@ -26,7 +26,7 @@ impl<T: Read> Stream<T> {
}
impl<T: Read> Responder for Stream<T> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> Outcome<'a> {
fn respond<'a>(&mut self, res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> {
let mut stream = res.start().unwrap();
let mut buffer = [0; CHUNK_SIZE];
let mut complete = false;
@ -55,6 +55,6 @@ impl<T: Read> Responder for Stream<T> {
return Outcome::FailStop;
}
Outcome::Complete
Outcome::Success
}
}

View File

@ -1,4 +1,4 @@
use response::{Responder, Outcome};
use response::{Responder, ResponseOutcome};
use http::hyper::{StatusCode, FreshHyperResponse};
pub struct StatusResponse<R: Responder> {
@ -16,7 +16,7 @@ impl<R: Responder> StatusResponse<R> {
}
impl<R: Responder> Responder for StatusResponse<R> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> Outcome<'b> {
fn respond<'b>(&mut self, mut res: FreshHyperResponse<'b>) -> ResponseOutcome<'b> {
*(res.status_mut()) = self.status;
self.responder.respond(res)
}

View File

@ -75,7 +75,7 @@ impl Rocket {
// Get the result if we failed forward so we can try again.
res = match outcome {
Outcome::Complete | Outcome::FailStop => return,
Outcome::Success | Outcome::FailStop => return,
Outcome::FailForward(r) => r,
Outcome::Bad(r) => return self.handle_internal_error(&request, r),
};