use std::borrow::{Borrow, Cow};
use std::ops::Deref;
use std::str::FromStr;
use std::fmt;
use header::Header;
use media_type::{MediaType, Source};
use ext::IntoCollection;
use hyper::mime::Mime;
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct ContentType(pub MediaType);
macro_rules! content_types {
($($name:ident ($check:ident): $str:expr, $t:expr,
$s:expr $(; $k:expr => $v:expr)*,)+) => {
$(
docify!([
Content Type for @{"**"}! @{$str}! @{"**"}!: @{"`"} @{$t}! @[/]! @{$s}!
$(; @{$k}! @[=]! @{$v}!)* @{"`"}!.
];
#[allow(non_upper_case_globals)]
pub const $name: ContentType = ContentType(MediaType::$name);
);
)+
}}
macro_rules! from_extension {
($($ext:expr => $name:ident,)*) => (
docify!([
Returns the @[Content-Type] associated with the extension @code{ext}.
Not all extensions are recognized. If an extensions is not recognized,
@code{None} is returned. The currently recognized extensions are:
@nl
$(* @{$ext} - @{"`ContentType::"}! @[$name]! @{"`"} @nl)*
@nl
This list is likely to grow. Extensions are matched
@[case-insensitively.]
];
#[inline]
pub fn from_extension(ext: &str) -> Option<ContentType> {
MediaType::from_extension(ext).map(ContentType)
}
);)
}
macro_rules! parse_flexible {
($($short:expr => $name:ident,)*) => (
docify!([
Flexibly parses @code{name} into a @code{ContentType}. The parse is
@[_flexible_] because, in addition to stricly correct content types, it
recognizes the following shorthands:
@nl
$(* $short - @{"`ContentType::"}! @[$name]! @{"`"} @nl)*
@nl
];
#[inline]
pub fn parse_flexible(name: &str) -> Option<ContentType> {
MediaType::parse_flexible(name).map(ContentType)
}
);)
}
impl ContentType {
#[inline(always)]
pub fn new<T, S>(top: T, sub: S) -> ContentType
where T: Into<Cow<'static, str>>, S: Into<Cow<'static, str>>
{
ContentType(MediaType::new(top, sub))
}
known_shorthands!(parse_flexible);
known_extensions!(from_extension);
#[inline]
pub fn with_params<T, S, K, V, P>(top: T, sub: S, ps: P) -> ContentType
where T: Into<Cow<'static, str>>, S: Into<Cow<'static, str>>,
K: Into<Cow<'static, str>>, V: Into<Cow<'static, str>>,
P: IntoCollection<(K, V)>
{
ContentType(MediaType::with_params(top, sub, ps))
}
#[inline(always)]
pub fn media_type(&self) -> &MediaType {
&self.0
}
known_media_types!(content_types);
}
impl Default for ContentType {
#[inline(always)]
fn default() -> ContentType {
ContentType::Any
}
}
impl Deref for ContentType {
type Target = MediaType;
#[inline(always)]
fn deref(&self) -> &MediaType {
&self.0
}
}
#[doc(hidden)]
impl<T: Borrow<Mime>> From<T> for ContentType {
#[inline(always)]
default fn from(mime: T) -> ContentType {
let mime: Mime = mime.borrow().clone();
ContentType::from(mime)
}
}
#[doc(hidden)]
impl From<Mime> for ContentType {
#[inline]
fn from(mime: Mime) -> ContentType {
let params = mime.2.into_iter()
.map(|(attr, value)| (attr.to_string(), value.to_string()))
.collect::<Vec<_>>();
ContentType::with_params(mime.0.to_string(), mime.1.to_string(), params)
}
}
impl FromStr for ContentType {
type Err = String;
#[inline(always)]
fn from_str(raw: &str) -> Result<ContentType, String> {
MediaType::from_str(raw).map(ContentType)
}
}
impl fmt::Display for ContentType {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Into<Header<'static>> for ContentType {
#[inline(always)]
fn into(self) -> Header<'static> {
if let Source::Known(src) = self.0.source {
Header::new("Content-Type", src)
} else {
Header::new("Content-Type", self.to_string())
}
}
}