mod constants;
mod parse;
pub use constants::*;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display};
use std::option;
use std::str::FromStr;
use crate::headers::{HeaderValue, ToHeaderValues};
use infer::Infer;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Mime {
pub(crate) essence: Cow<'static, str>,
pub(crate) basetype: Cow<'static, str>,
pub(crate) subtype: Cow<'static, str>,
pub(crate) is_utf8: bool,
pub(crate) params: Vec<(ParamName, ParamValue)>,
}
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"),
};
Mime::from_str(&mime)
}
pub fn from_extension(extension: impl AsRef<str>) -> Option<Self> {
match extension.as_ref() {
"html" => Some(HTML),
"js" | "mjs" | "jsonp" => Some(JAVASCRIPT),
"json" => Some(JSON),
"css" => Some(CSS),
"svg" => Some(SVG),
"xml" => Some(XML),
_ => None,
}
}
pub fn basetype(&self) -> &str {
&self.basetype
}
pub fn subtype(&self) -> &str {
&self.subtype
}
pub fn essence(&self) -> &str {
&self.essence
}
pub fn param(&self, name: impl Into<ParamName>) -> Option<&ParamValue> {
let name: ParamName = name.into();
if name.as_str() == "charset" && self.is_utf8 {
return Some(&ParamValue(Cow::Borrowed("utf-8")));
}
self.params.iter().find(|(k, _)| k == &name).map(|(_, v)| v)
}
pub fn remove_param(&mut self, name: impl Into<ParamName>) -> Option<ParamValue> {
let name: ParamName = name.into();
if name.as_str() == "charset" && self.is_utf8 {
self.is_utf8 = false;
return Some(ParamValue(Cow::Borrowed("utf-8")));
}
self.params
.iter()
.position(|(k, _)| k == &name)
.map(|pos| self.params.remove(pos).1)
}
}
impl Display for Mime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
parse::format(self, f)
}
}
impl FromStr for Mime {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
parse::parse(s)
}
}
impl<'a> From<&'a str> for Mime {
fn from(value: &'a str) -> Self {
Self::from_str(value).unwrap()
}
}
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())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ParamName(Cow<'static, str>);
impl ParamName {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Display for ParamName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl FromStr for ParamName {
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(ParamName(Cow::Owned(s.to_ascii_lowercase())))
}
}
impl<'a> From<&'a str> for ParamName {
fn from(value: &'a str) -> Self {
Self::from_str(value).unwrap()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ParamValue(Cow<'static, str>);
impl ParamValue {
pub fn as_str(&self) -> &str {
&self.0
}
}
impl Display for ParamValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl<'a> PartialEq<&'a str> for ParamValue {
fn eq(&self, other: &&'a str) -> bool {
&self.0 == other
}
}
impl PartialEq<str> for ParamValue {
fn eq(&self, other: &str) -> bool {
self.0 == other
}
}