From bd9d553050983a4fb885809fca006c9b7c5d7afd Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Mon, 22 Aug 2016 20:34:22 -0700 Subject: [PATCH] New type: ContentType. Parse ContentType from attribute. --- Cargo.toml | 1 + lib/Cargo.toml | 1 + lib/src/codegen.rs | 7 +-- lib/src/content_type.rs | 78 ++++++++++++++++++++++++++++++++++ lib/src/lib.rs | 3 ++ lib/src/router/route.rs | 18 +++++--- macros/src/meta_item_parser.rs | 17 ++++++-- macros/src/route_decorator.rs | 6 ++- 8 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 lib/src/content_type.rs diff --git a/Cargo.toml b/Cargo.toml index ef94219d..ae030935 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ members = [ "examples/redirect", "examples/static_files", "examples/todo", + "examples/content_types", ] diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 6628dc04..fe781115 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -7,6 +7,7 @@ authors = ["Sergio Benitez "] term-painter = "*" hyper = "*" url = "*" +mime = "*" # [dependencies.hyper] # git = "https://github.com/hyperium/hyper.git" diff --git a/lib/src/codegen.rs b/lib/src/codegen.rs index 585a3fb9..5b43f493 100644 --- a/lib/src/codegen.rs +++ b/lib/src/codegen.rs @@ -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 { diff --git a/lib/src/content_type.rs b/lib/src/content_type.rs new file mode 100644 index 00000000..5c7f1da4 --- /dev/null +++ b/lib/src/content_type.rs @@ -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>); + +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 for ContentType { + fn into(self) -> Mime { + Mime(self.0, self.1, self.2.unwrap_or_default()) + } +} + +impl From 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 { + let mime = Mime::from_str(raw)?; + Ok(ContentType::from(mime)) + } +} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index c1750e03..14c768aa 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -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; diff --git a/lib/src/router/route.rs b/lib/src/router/route.rs index 1168ccf4..d45d1c76 100644 --- a/lib/src/router/route.rs +++ b/lib/src/router/route.rs @@ -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(rank: isize, m: Method, path: S, handler: Handler) + pub fn ranked(rank: isize, m: Method, path: S, handler: Handler, t: ContentType) -> Route where S: AsRef { 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(), } } diff --git a/macros/src/meta_item_parser.rs b/macros/src/meta_item_parser.rs index 023d4a44..414b596f 100644 --- a/macros/src/meta_item_parser.rs +++ b/macros/src/meta_item_parser.rs @@ -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, pub path: KVSpanned, pub form: Option>, - pub content_type: Option>, + pub content_type: Option>, } 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); diff --git a/macros/src/route_decorator.rs b/macros/src/route_decorator.rs index 3feeb704..5d79e45b 100644 --- a/macros/src/route_decorator.rs +++ b/macros/src/route_decorator.rs @@ -217,7 +217,11 @@ pub fn route_decorator(known_method: Option>, 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())); }