use std::borrow::Cow;
use std::ops::Deref;
use std::str::FromStr;
use std::fmt;
use crate::header::{Header, MediaType};
use crate::uncased::UncasedStr;
use crate::ext::IntoCollection;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ContentType(pub MediaType);
macro_rules! content_types {
(
$(
$name:ident ($check:ident): $str:expr,
$t:expr, $s:expr $(; $k:expr => $v:expr)*,
)+
) => {
$(
/// Content Type for
#[doc = concat!("**", $str, "**: ")]
#[doc = concat!("`", $t, "/", $s, $("; ", $k, "=", $v,)* "`")]
#[allow(non_upper_case_globals)]
pub const $name: ContentType = ContentType(MediaType::$name);
)+
}}
macro_rules! from_extension {
($($ext:expr => $name:ident,)*) => (
$(
#[doc = concat!("* ", $ext, " - [`ContentType::", stringify!($name), "`]")]
)*
#[inline]
pub fn from_extension(ext: &str) -> Option<ContentType> {
MediaType::from_extension(ext).map(ContentType)
}
)
}
macro_rules! extension {
($($ext:expr => $name:ident,)*) => (
#[inline]
pub fn extension(&self) -> Option<&UncasedStr> {
$(if self == &ContentType::$name { return Some($ext.into()) })*
None
}
)
}
macro_rules! parse_flexible {
($($short:expr => $name:ident,)*) => (
$(
#[doc = concat!("* ", $short, " - [`ContentType::", stringify!($name), "`]")]
)*
#[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);
pub fn with_params<K, V, P>(self, parameters: P) -> ContentType
where K: Into<Cow<'static, str>>,
V: Into<Cow<'static, str>>,
P: IntoCollection<(K, V)>
{
ContentType(self.0.with_params(parameters))
}
#[inline(always)]
pub fn media_type(&self) -> &MediaType {
&self.0
}
known_extensions!(extension);
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
}
}
impl FromStr for ContentType {
type Err = String;
#[inline(always)]
fn from_str(raw: &str) -> Result<ContentType, String> {
MediaType::from_str(raw).map(ContentType)
}
}
impl From<MediaType> for ContentType {
fn from(media_type: MediaType) -> Self {
ContentType(media_type)
}
}
impl fmt::Display for ContentType {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<ContentType> for Header<'static> {
#[inline(always)]
fn from(content_type: ContentType) -> Self {
if let Some(src) = content_type.known_source() {
Header::new("Content-Type", src)
} else {
Header::new("Content-Type", content_type.to_string())
}
}
}