New type: ContentType. Parse ContentType from attribute.

This commit is contained in:
Sergio Benitez 2016-08-22 20:34:22 -07:00
parent c8eef33820
commit bd9d553050
8 changed files with 117 additions and 14 deletions

View File

@ -13,4 +13,5 @@ members = [
"examples/redirect", "examples/redirect",
"examples/static_files", "examples/static_files",
"examples/todo", "examples/todo",
"examples/content_types",
] ]

View File

@ -7,6 +7,7 @@ authors = ["Sergio Benitez <sb@sergio.bz>"]
term-painter = "*" term-painter = "*"
hyper = "*" hyper = "*"
url = "*" url = "*"
mime = "*"
# [dependencies.hyper] # [dependencies.hyper]
# git = "https://github.com/hyperium/hyper.git" # git = "https://github.com/hyperium/hyper.git"

View File

@ -1,10 +1,11 @@
use method::Method; use ::{Method, Handler};
use handler::Handler; use content_type::ContentType;
pub struct StaticRouteInfo { pub struct StaticRouteInfo {
pub method: Method, pub method: Method,
pub path: &'static str, pub path: &'static str,
pub handler: Handler pub content_type: ContentType,
pub handler: Handler,
} }
pub struct StaticCatchInfo { pub struct StaticCatchInfo {

78
lib/src/content_type.rs Normal file
View File

@ -0,0 +1,78 @@
pub use mime::{Mime, TopLevel, SubLevel};
use std::str::FromStr;
use mime::{Param};
use self::TopLevel::{Text, Application};
use self::SubLevel::{Json, Html};
#[derive(Debug, Clone)]
pub struct ContentType(pub TopLevel, pub SubLevel, pub Option<Vec<Param>>);
impl ContentType {
#[inline(always)]
pub fn of(t: TopLevel, s: SubLevel) -> ContentType {
ContentType(t, s, None)
}
#[inline(always)]
pub fn any() -> ContentType {
ContentType::of(TopLevel::Star, SubLevel::Star)
}
pub fn is_json(&self) -> bool {
match *self {
ContentType(Application, Json, _) => true,
_ => false,
}
}
pub fn is_any(&self) -> bool {
match *self {
ContentType(TopLevel::Star, SubLevel::Star, None) => true,
_ => false,
}
}
pub fn is_ext(&self) -> bool {
if let TopLevel::Ext(_) = self.0 {
true
} else if let SubLevel::Ext(_) = self.1 {
true
} else {
false
}
}
pub fn is_html(&self) -> bool {
match *self {
ContentType(Text, Html, _) => true,
_ => false,
}
}
}
impl Into<Mime> for ContentType {
fn into(self) -> Mime {
Mime(self.0, self.1, self.2.unwrap_or_default())
}
}
impl From<Mime> for ContentType {
fn from(mime: Mime) -> ContentType {
let params = match mime.2.len() {
0 => None,
_ => Some(mime.2)
};
ContentType(mime.0, mime.1, params)
}
}
impl FromStr for ContentType {
type Err = ();
fn from_str(raw: &str) -> Result<ContentType, ()> {
let mime = Mime::from_str(raw)?;
Ok(ContentType::from(mime))
}
}

View File

@ -4,6 +4,7 @@
extern crate term_painter; extern crate term_painter;
extern crate hyper; extern crate hyper;
extern crate url; extern crate url;
extern crate mime;
mod method; mod method;
mod error; mod error;
@ -16,6 +17,7 @@ mod catcher;
pub mod form; pub mod form;
pub mod request; pub mod request;
pub mod response; pub mod response;
pub mod content_type;
pub mod handler { pub mod handler {
use super::{Request, Response}; use super::{Request, Response};
@ -23,6 +25,7 @@ pub mod handler {
pub type Handler = for<'r> fn(Request<'r>) -> Response<'r>; pub type Handler = for<'r> fn(Request<'r>) -> Response<'r>;
} }
pub use content_type::ContentType;
pub use codegen::{StaticRouteInfo, StaticCatchInfo}; pub use codegen::{StaticRouteInfo, StaticCatchInfo};
pub use request::Request; pub use request::Request;
pub use method::Method; pub use method::Method;

View File

@ -1,9 +1,10 @@
use ::{Method, Handler, StaticRouteInfo};
use content_type::ContentType;
use super::{Collider, URI, URIBuf}; // :D
use term_painter::ToStyle; use term_painter::ToStyle;
use term_painter::Color::*; use term_painter::Color::*;
use method::Method;
use super::{Collider, URI, URIBuf}; // :D
use handler::Handler;
use codegen::StaticRouteInfo;
use std::fmt; use std::fmt;
use std::convert::From; use std::convert::From;
@ -11,17 +12,19 @@ pub struct Route {
pub method: Method, pub method: Method,
pub handler: Handler, pub handler: Handler,
pub path: URIBuf, pub path: URIBuf,
pub rank: isize pub rank: isize,
pub content_type: ContentType,
} }
impl Route { impl Route {
pub fn ranked<S>(rank: isize, m: Method, path: S, handler: Handler) pub fn ranked<S>(rank: isize, m: Method, path: S, handler: Handler, t: ContentType)
-> Route where S: AsRef<str> { -> Route where S: AsRef<str> {
Route { Route {
method: m, method: m,
path: URIBuf::from(path.as_ref()), path: URIBuf::from(path.as_ref()),
handler: handler, handler: handler,
rank: rank rank: rank,
content_type: t,
} }
} }
@ -32,6 +35,7 @@ impl Route {
handler: handler, handler: handler,
rank: (!path.as_ref().contains('<') as isize), rank: (!path.as_ref().contains('<') as isize),
path: URIBuf::from(path.as_ref()), path: URIBuf::from(path.as_ref()),
content_type: ContentType::any(),
} }
} }

View File

@ -6,7 +6,7 @@ use syntax::codemap::{Span, Spanned, BytePos};
use syntax::ptr::P; use syntax::ptr::P;
use utils::*; use utils::*;
use rocket::Method; use rocket::{Method, ContentType};
#[allow(dead_code)] #[allow(dead_code)]
const DEBUG: bool = true; const DEBUG: bool = true;
@ -122,7 +122,7 @@ pub struct RouteParams {
pub method: Spanned<Method>, pub method: Spanned<Method>,
pub path: KVSpanned<String>, pub path: KVSpanned<String>,
pub form: Option<KVSpanned<String>>, pub form: Option<KVSpanned<String>>,
pub content_type: Option<KVSpanned<String>>, pub content_type: Option<KVSpanned<ContentType>>,
} }
pub trait RouteDecoratorExt { pub trait RouteDecoratorExt {
@ -206,7 +206,18 @@ impl<'a, 'c> RouteDecoratorExt for MetaItemParser<'a, 'c> {
}); });
let content_type = kv_pairs.get("content").and_then(|data| { let content_type = kv_pairs.get("content").and_then(|data| {
Some(data.clone().map(String::from)) if let Ok(ct) = ContentType::from_str(data.node) {
if ct.is_ext() {
let msg = format!("'{}' is not a known content-type", data.node);
self.ctxt.span_warn(data.v_span, &msg);
}
Some(data.clone().map(|_| ct))
} else {
let msg = format!("'{}' is not a valid content-type", data.node);
self.ctxt.span_err(data.v_span, &msg);
None
}
}); });
debug!("Found data: {:?}", content_type); debug!("Found data: {:?}", content_type);

View File

@ -217,7 +217,11 @@ pub fn route_decorator(known_method: Option<Spanned<Method>>, ecx: &mut ExtCtxt,
::rocket::StaticRouteInfo { ::rocket::StaticRouteInfo {
method: $method, method: $method,
path: $path, path: $path,
handler: $route_fn_name handler: $route_fn_name,
content_type: ::rocket::ContentType(
::rocket::content_type::TopLevel::Star,
::rocket::content_type::SubLevel::Star,
None)
}; };
).unwrap())); ).unwrap()));
} }