From 57f79ca8678a5b736cc3fa4d2b80063b9a0fb70e Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 30 Sep 2016 20:04:43 -0700 Subject: [PATCH] Document ContentType. --- lib/src/content_type.rs | 117 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 2 deletions(-) diff --git a/lib/src/content_type.rs b/lib/src/content_type.rs index 41cbb83b..d445051d 100644 --- a/lib/src/content_type.rs +++ b/lib/src/content_type.rs @@ -8,11 +8,20 @@ use std::fmt; use router::Collider; -#[derive(Debug, Clone)] -pub struct ContentType(pub TopLevel, pub SubLevel, pub Option>); +/// Rocket's representation of HTTP Content-Types. +/// +/// This type wraps raw HTTP `Content-Type`s in a type-safe manner. It provides +/// methods to create and test against common HTTP content-types. It also +/// provides methods to parse HTTP Content-Type values +/// ([from_str](#method.from_str)) and to return the ContentType associated with +/// a file extension ([from_ext](#method.from_extension)). +#[derive(Debug, Clone, PartialEq)] +pub struct ContentType(pub TopLevel, pub SubLevel, Option>); macro_rules! is_some { ($ct:ident, $name:ident: $top:ident/$sub:ident) => { + /// Returns a new ContentType that matches the MIME for this method's + /// name. pub fn $ct() -> ContentType { ContentType::of(TopLevel::$top, SubLevel::$sub) } @@ -21,6 +30,8 @@ macro_rules! is_some { }; ($name:ident: $top:ident/$sub:ident) => { + /// Returns true if `self` is the content type matching the method's + /// name. pub fn $name(&self) -> bool { self.0 == TopLevel::$top && self.1 == SubLevel::$sub } @@ -28,21 +39,37 @@ macro_rules! is_some { } impl ContentType { + #[doc(hidden)] #[inline(always)] pub fn new(t: TopLevel, s: SubLevel, params: Option>) -> ContentType { ContentType(t, s, params) } + /// Constructs a new content type of the given top level and sub level + /// types. + /// + /// # Examples + /// + /// ```rust + /// use rocket::ContentType; + /// use rocket::response::mime::{TopLevel, SubLevel}; + /// + /// let html = ContentType::of(TopLevel::Application, SubLevel::Html); + /// assert!(html.is_html()); + /// ``` #[inline(always)] pub fn of(t: TopLevel, s: SubLevel) -> ContentType { ContentType(t, s, None) } + /// Returns a new ContentType for `*/*`, i.e., any. #[inline(always)] pub fn any() -> ContentType { ContentType::of(TopLevel::Star, SubLevel::Star) } + /// Returns true if this content type is not one of the standard content + /// types, that if, if it is an "extended" content type. pub fn is_ext(&self) -> bool { if let TopLevel::Ext(_) = self.0 { true @@ -53,13 +80,49 @@ impl ContentType { } } + /// Returns true if the content type is JSON, i.e: `application/json`. is_some!(json, is_json: Application/Json); + + /// Returns true if the content type is XML, i.e: `application/xml`. is_some!(xml, is_xml: Application/Xml); + + /// Returns true if the content type is any, i.e.: `*/*`. is_some!(is_any: Star/Star); + + /// Returns true if the content type is HTML, i.e.: `application/html`. is_some!(html, is_html: Application/Html); + + /// Returns true if the content type is that for non-data HTTP forms, i.e.: + /// `application/x-www-form-urlencoded`. is_some!(is_form: Application/WwwFormUrlEncoded); + + /// Returns true if the content type is that for data HTTP forms, i.e.: + /// `multipart/form-data`. is_some!(is_data: Multipart/FormData); + /// Returns the Content-Type associated with the extension `ext`. Not all + /// extensions are recognized. If an extensions is not recognized, then this + /// method returns a ContentType of `any`. + /// + /// # Example + /// + /// A recognized content type: + /// + /// ```rust + /// use rocket::ContentType; + /// + /// let xml = ContentType::from_extension("xml"); + /// assert!(xml.is_xml()); + /// ``` + /// + /// An unrecognized content type: + /// + /// ```rust + /// use rocket::ContentType; + /// + /// let foo = ContentType::from_extension("foo"); + /// assert!(foo.is_any()); + /// ``` pub fn from_extension(ext: &str) -> ContentType { let (top_level, sub_level) = match ext { "txt" => (TopLevel::Text, SubLevel::Plain), @@ -82,18 +145,21 @@ impl ContentType { } impl Default for ContentType { + /// Returns a ContentType of `any`, or `*/*`. #[inline(always)] fn default() -> ContentType { ContentType::any() } } +#[doc(hidden)] impl Into for ContentType { fn into(self) -> Mime { Mime(self.0, self.1, self.2.unwrap_or_default()) } } +#[doc(hidden)] impl> From for ContentType { default fn from(mime: T) -> ContentType { let mime: Mime = mime.borrow().clone(); @@ -101,6 +167,7 @@ impl> From for ContentType { } } +#[doc(hidden)] impl From for ContentType { fn from(mime: Mime) -> ContentType { let params = match mime.2.len() { @@ -129,6 +196,42 @@ fn is_valid_char(c: char) -> bool { impl FromStr for ContentType { type Err = &'static str; + /// Parses a ContentType from a given Content-Type header value. + /// + /// # Examples + /// + /// Parsing an `application/json`: + /// + /// ```rust + /// use rocket::ContentType; + /// use std::str::FromStr; + /// + /// let json = ContentType::from_str("application/json"); + /// assert_eq!(json, Ok(ContentType::json())); + /// ``` + /// + /// Parsing a content-type extension: + /// + /// ```rust + /// use rocket::ContentType; + /// use std::str::FromStr; + /// use rocket::response::mime::{TopLevel, SubLevel}; + /// + /// let custom = ContentType::from_str("application/x-custom").unwrap(); + /// assert!(custom.is_ext()); + /// assert_eq!(custom.0, TopLevel::Application); + /// assert_eq!(custom.1, SubLevel::Ext("x-custom".into())); + /// ``` + /// + /// Parsing an invalid Content-Type value: + /// + /// ```rust + /// use rocket::ContentType; + /// use std::str::FromStr; + /// + /// let custom = ContentType::from_str("application//x-custom"); + /// assert!(custom.is_err()); + /// ``` fn from_str(raw: &str) -> Result { let slash = match raw.find('/') { Some(i) => i, @@ -165,6 +268,16 @@ impl FromStr for ContentType { } impl fmt::Display for ContentType { + /// Formats the ContentType as an HTTP Content-Type value. + /// + /// # Example + /// + /// ```rust + /// use rocket::ContentType; + /// + /// let http_ct = format!("{}", ContentType::xml()); + /// assert_eq!(http_ct, "application/xml".to_string()); + /// ``` fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}/{}", self.0.as_str(), self.1.as_str())?;