mod constants;
mod parse;
pub use constants::*;
use std::collections::HashMap;
use std::fmt::{self, Debug, Display};
use std::option;
use std::str::FromStr;
use crate::headers::{HeaderValue, ToHeaderValues};
use infer::Infer;
#[derive(Clone)]
pub struct Mime {
pub(crate) essence: String,
pub(crate) basetype: String,
pub(crate) subtype: String,
pub(crate) static_essence: Option<&'static str>,
pub(crate) static_basetype: Option<&'static str>,
pub(crate) static_subtype: Option<&'static str>,
pub(crate) parameters: Option<HashMap<String, String>>,
}
impl Mime {
pub fn sniff(bytes: &[u8]) -> crate::Result<Self> {
let info = Infer::new();
let mime = match info.get(&bytes) {
Some(info) => info.mime,
None => crate::bail!("Could not sniff the mime type"),
};
Ok(Self {
essence: mime,
static_essence: None,
basetype: String::new(), subtype: String::new(), static_basetype: None, static_subtype: None,
parameters: None, })
}
pub fn basetype(&self) -> &str {
if let Some(basetype) = self.static_basetype {
&basetype
} else {
&self.basetype
}
}
pub fn subtype(&self) -> &str {
if let Some(subtype) = self.static_subtype {
&subtype
} else {
&self.subtype
}
}
pub fn essence(&self) -> &str {
if let Some(essence) = self.static_essence {
&essence
} else {
&self.essence
}
}
pub fn param(&self, s: &str) -> Option<&String> {
self.parameters.as_ref().map(|hm| hm.get(s)).flatten()
}
pub fn param_mut(&mut self, s: &str) -> Option<&mut String> {
self.parameters.as_mut().map(|hm| hm.get_mut(s)).flatten()
}
}
impl Display for Mime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(essence) = self.static_essence {
write!(f, "{}", essence)?
} else {
write!(f, "{}", &self.essence)?
}
if let Some(parameters) = &self.parameters {
assert!(!parameters.is_empty());
write!(f, "; ")?;
for (i, (key, value)) in parameters.iter().enumerate() {
write!(f, "{}={}", key, value)?;
if i != parameters.len() - 1 {
write!(f, ",")?;
}
}
}
Ok(())
}
}
impl Debug for Mime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(essence) = self.static_essence {
Debug::fmt(essence, f)
} else {
Debug::fmt(&self.essence, f)
}
}
}
impl FromStr for Mime {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::ensure!(s.is_ascii(), "String slice should be valid ASCII");
Ok(Self {
essence: s.to_ascii_lowercase(),
static_essence: None,
basetype: String::new(), subtype: String::new(), static_basetype: None, static_subtype: None, parameters: None, })
}
}
impl ToHeaderValues for Mime {
type Iter = option::IntoIter<HeaderValue>;
fn to_header_values(&self) -> crate::Result<Self::Iter> {
let mime = self.clone();
let header: HeaderValue = mime.into();
Ok(header.to_header_values().unwrap())
}
}