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/static_files",
"examples/todo",
"examples/content_types",
]

View File

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

View File

@ -1,10 +1,11 @@
use method::Method;
use handler::Handler;
use ::{Method, Handler};
use content_type::ContentType;
pub struct StaticRouteInfo {
pub method: Method,
pub path: &'static str,
pub handler: Handler
pub content_type: ContentType,
pub handler: Handler,
}
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 hyper;
extern crate url;
extern crate mime;
mod method;
mod error;
@ -16,6 +17,7 @@ mod catcher;
pub mod form;
pub mod request;
pub mod response;
pub mod content_type;
pub mod handler {
use super::{Request, Response};
@ -23,6 +25,7 @@ pub mod handler {
pub type Handler = for<'r> fn(Request<'r>) -> Response<'r>;
}
pub use content_type::ContentType;
pub use codegen::{StaticRouteInfo, StaticCatchInfo};
pub use request::Request;
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::Color::*;
use method::Method;
use super::{Collider, URI, URIBuf}; // :D
use handler::Handler;
use codegen::StaticRouteInfo;
use std::fmt;
use std::convert::From;
@ -11,17 +12,19 @@ pub struct Route {
pub method: Method,
pub handler: Handler,
pub path: URIBuf,
pub rank: isize
pub rank: isize,
pub content_type: ContentType,
}
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 {
method: m,
path: URIBuf::from(path.as_ref()),
handler: handler,
rank: rank
rank: rank,
content_type: t,
}
}
@ -32,6 +35,7 @@ impl Route {
handler: handler,
rank: (!path.as_ref().contains('<') as isize),
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 utils::*;
use rocket::Method;
use rocket::{Method, ContentType};
#[allow(dead_code)]
const DEBUG: bool = true;
@ -122,7 +122,7 @@ pub struct RouteParams {
pub method: Spanned<Method>,
pub path: KVSpanned<String>,
pub form: Option<KVSpanned<String>>,
pub content_type: Option<KVSpanned<String>>,
pub content_type: Option<KVSpanned<ContentType>>,
}
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| {
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);

View File

@ -217,7 +217,11 @@ pub fn route_decorator(known_method: Option<Spanned<Method>>, ecx: &mut ExtCtxt,
::rocket::StaticRouteInfo {
method: $method,
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()));
}