use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
#[derive(Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Debug, Hash)]
#[repr(transparent)]
pub struct QValue(u16);
impl QValue {
pub const MAX: QValue = QValue(1000);
pub const MIN: QValue = QValue(0);
pub fn parse(qvalue: impl AsRef<str>) -> Option<QValue> {
let qvalue = qvalue.as_ref();
match qvalue.len() {
1 => {
if qvalue == "1" {
return Some(QValue(1000));
}
if qvalue == "0" {
return Some(QValue(0));
}
None
}
2 => None,
3 => {
if !qvalue.starts_with("0.") {
if qvalue == "1.0" {
return Some(QValue(1000));
}
return None;
}
if let Ok(value) = qvalue[2..].parse::<u16>() {
return Some(QValue(value * 100));
}
None
}
4 => {
if !qvalue.starts_with("0.") {
if qvalue == "1.00" {
return Some(QValue(1000));
}
return None;
}
if let Ok(value) = qvalue[2..].parse::<u16>() {
return Some(QValue(value * 10));
}
None
}
5 => {
if !qvalue.starts_with("0.") {
if qvalue == "1.000" {
return Some(QValue(1000));
}
return None;
}
if let Ok(value) = qvalue[2..].parse::<u16>() {
return Some(QValue(value));
}
None
}
_ => None,
}
}
pub const fn as_str(&self) -> &'static str {
tii_procmacro::qvalue_to_strs!()
}
pub const fn as_u16(&self) -> u16 {
self.0
}
pub const fn from_clamped(qvalue: u16) -> QValue {
if qvalue > 1000 {
return QValue(1000);
}
QValue(qvalue)
}
}
impl Display for QValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl Default for QValue {
fn default() -> Self {
QValue(1000)
}
}
#[derive(Clone, PartialEq, Debug, Eq, Hash)]
pub enum AcceptMimeType {
GroupWildcard(MimeGroup),
Specific(MimeType),
Wildcard,
}
impl AsRef<AcceptMimeType> for AcceptMimeType {
fn as_ref(&self) -> &AcceptMimeType {
self
}
}
impl AcceptMimeType {
pub fn parse(value: impl AsRef<str>) -> Option<AcceptMimeType> {
let mime = value.as_ref();
let mime = mime.split_once(";").map(|(mime, _)| mime).unwrap_or(mime);
if mime == "*/*" {
return Some(AcceptMimeType::Wildcard);
}
match MimeType::parse(mime) {
None => match MimeGroup::parse(mime) {
Some(group) => {
if &mime[group.as_str().len()..] != "/*" {
return None;
}
Some(AcceptMimeType::GroupWildcard(group))
}
None => None,
},
Some(mime) => Some(AcceptMimeType::Specific(mime)),
}
}
pub fn permits_specific(&self, mime_type: impl AsRef<MimeType>) -> bool {
match self {
AcceptMimeType::GroupWildcard(group) => group == mime_type.as_ref().mime_group(),
AcceptMimeType::Specific(mime) => mime == mime_type.as_ref(),
AcceptMimeType::Wildcard => true,
}
}
pub fn permits_group(&self, mime_group: impl AsRef<MimeGroup>) -> bool {
match self {
AcceptMimeType::GroupWildcard(group) => group == mime_group.as_ref(),
AcceptMimeType::Specific(_) => false,
AcceptMimeType::Wildcard => true,
}
}
pub fn permits(&self, mime_type: impl AsRef<AcceptMimeType>) -> bool {
match mime_type.as_ref() {
AcceptMimeType::GroupWildcard(group) => self.permits_group(group),
AcceptMimeType::Specific(mime) => self.permits_specific(mime),
AcceptMimeType::Wildcard => matches!(self, AcceptMimeType::Wildcard),
}
}
}
impl Display for AcceptMimeType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AcceptMimeType::GroupWildcard(group) => {
f.write_str(group.as_str())?;
f.write_str("/*")?;
}
AcceptMimeType::Specific(mime) => {
f.write_str(mime.as_str())?;
}
AcceptMimeType::Wildcard => f.write_str("*/*")?,
}
Ok(())
}
}
#[derive(Clone, PartialEq, Debug, Eq, Hash)]
pub struct AcceptMimeTypeWithCharset {
mime: AcceptMimeType,
charset: MimeCharset,
}
impl AcceptMimeTypeWithCharset {
pub const fn new(mime: AcceptMimeType, charset: MimeCharset) -> Self {
Self { mime, charset }
}
pub const fn mime(&self) -> &AcceptMimeType {
&self.mime
}
pub const fn charset(&self) -> &MimeCharset {
&self.charset
}
pub const fn has_charset(&self) -> bool {
!matches!(self.charset, MimeCharset::Unspecified)
}
}
impl<T> From<T> for AcceptMimeTypeWithCharset
where
T: Into<AcceptMimeType>,
{
fn from(value: T) -> Self {
AcceptMimeTypeWithCharset::new(value.into(), MimeCharset::Unspecified)
}
}
impl<T, Y> From<(T, Y)> for AcceptMimeTypeWithCharset
where
T: Into<AcceptMimeType>,
Y: Into<MimeCharset>,
{
fn from(value: (T, Y)) -> Self {
AcceptMimeTypeWithCharset::new(value.0.into(), value.1.into())
}
}
#[derive(Clone, PartialEq, Debug, Eq)]
pub struct AcceptQualityMimeType {
value: AcceptMimeType,
charset: MimeCharset,
q: QValue,
}
impl PartialOrd<Self> for AcceptQualityMimeType {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AcceptQualityMimeType {
fn cmp(&self, other: &Self) -> Ordering {
other.q.cmp(&self.q)
}
}
impl AcceptQualityMimeType {
pub fn parse(value: impl AsRef<str>) -> Option<Vec<Self>> {
let mut stack_buffer = [0u8; 8];
let value = value.as_ref();
let mut data = Vec::new();
for mut accept_mime in value.split(",") {
accept_mime = accept_mime.trim();
let mut iter = accept_mime.split(";");
let mime = iter.next()?;
let mut q = None;
let mut charset = None;
for raw_part in iter.map(str::trim) {
if raw_part.starts_with("q=") {
if q.is_some() {
return None;
}
q = Some(QValue::parse(raw_part.get(2..)?)?);
continue;
}
if crate::util::ascii_to_lower_first_n(&mut stack_buffer, raw_part).starts_with("charset=")
{
if charset.is_some() {
return None;
}
charset = Some(MimeCharset::parse(raw_part.get(8..)?)?);
continue;
}
return None;
}
let q = q.unwrap_or_default();
let charset = charset.unwrap_or_default();
if mime == "*/*" {
data.push(AcceptQualityMimeType { value: AcceptMimeType::Wildcard, q, charset });
continue;
}
match MimeType::parse(mime) {
None => match MimeGroup::parse(mime) {
Some(group) => {
if &mime[group.as_str().len()..] != "/*" {
return None;
}
data.push(AcceptQualityMimeType {
value: AcceptMimeType::GroupWildcard(group),
q,
charset,
})
}
None => return None,
},
Some(mime) => {
data.push(AcceptQualityMimeType { value: AcceptMimeType::Specific(mime), q, charset })
}
};
}
data.sort();
Some(data)
}
pub fn elements_to_header_value(elements: &Vec<Self>) -> String {
let mut buffer = String::new();
for element in elements {
if !buffer.is_empty() {
buffer += ",";
}
buffer += element.to_string().as_str();
}
buffer
}
pub fn get_type(&self) -> &AcceptMimeType {
&self.value
}
pub const fn qvalue(&self) -> QValue {
self.q
}
pub const fn charset(&self) -> &MimeCharset {
&self.charset
}
pub const fn is_wildcard(&self) -> bool {
matches!(self.value, AcceptMimeType::Wildcard)
}
pub const fn is_group_wildcard(&self) -> bool {
matches!(self.value, AcceptMimeType::GroupWildcard(_))
}
pub const fn is_specific(&self) -> bool {
matches!(self.value, AcceptMimeType::Specific(_))
}
pub const fn mime(&self) -> Option<&MimeType> {
match &self.value {
AcceptMimeType::Specific(mime) => Some(mime),
_ => None,
}
}
pub const fn group(&self) -> Option<&MimeGroup> {
match &self.value {
AcceptMimeType::Specific(mime) => Some(mime.mime_group()),
AcceptMimeType::GroupWildcard(group) => Some(group),
_ => None,
}
}
pub const fn wildcard(q: QValue, charset: MimeCharset) -> AcceptQualityMimeType {
AcceptQualityMimeType { value: AcceptMimeType::Wildcard, q, charset }
}
pub const fn from_group(
group: MimeGroup,
q: QValue,
charset: MimeCharset,
) -> AcceptQualityMimeType {
AcceptQualityMimeType { value: AcceptMimeType::GroupWildcard(group), q, charset }
}
pub const fn from_mime(mime: MimeType, q: QValue, charset: MimeCharset) -> AcceptQualityMimeType {
AcceptQualityMimeType { value: AcceptMimeType::Specific(mime), q, charset }
}
pub const fn from_accept_mime(
mime: AcceptMimeType,
q: QValue,
charset: MimeCharset,
) -> AcceptQualityMimeType {
AcceptQualityMimeType { value: mime, q, charset }
}
}
impl Default for AcceptQualityMimeType {
fn default() -> Self {
AcceptQualityMimeType::wildcard(QValue::default(), MimeCharset::default())
}
}
impl Display for AcceptQualityMimeType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.value, f)?;
if self.q.as_u16() != 1000 {
f.write_str(";q=")?;
f.write_str(self.q.as_str())?;
}
Ok(())
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)]
#[non_exhaustive]
pub enum MimeCharset {
Utf8,
Iso88591,
UsAscii,
#[default]
Unspecified,
Other(String),
}
impl MimeCharset {
pub fn as_str(&self) -> Option<&str> {
Some(match self {
MimeCharset::Unspecified => return None,
MimeCharset::Utf8 => "UTF-8",
MimeCharset::UsAscii => "US-ASCII",
MimeCharset::Iso88591 => "ISO-8859-1",
MimeCharset::Other(s) => s,
})
}
pub fn parse(data: impl AsRef<str>) -> Option<Self> {
let data = data.as_ref();
let mut stack_buffer = [0u8; 16];
Some(match crate::util::ascii_to_lower_first_n(&mut stack_buffer, data) {
"utf-8" | "utf8" => MimeCharset::Utf8,
"iso-8859-1" => MimeCharset::Iso88591,
"us-ascii" => MimeCharset::UsAscii,
"" => MimeCharset::Unspecified,
_ => {
for c in data.chars() {
if c.is_ascii_digit() {
continue;
}
if c.is_ascii_alphabetic() {
continue;
}
if c == '-' || c == '_' || c == '.' || c == '(' || c == ')' || c == ':' {
continue;
}
return None;
}
MimeCharset::Other(data.to_string())
}
})
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)]
pub struct AcceptMimeCharset {
charset: MimeCharset,
q: QValue,
}
impl AcceptMimeCharset {
pub fn parse(value: impl AsRef<str>) -> Option<Vec<Self>> {
let value = value.as_ref().trim();
if value.is_empty() {
return Some(vec![]);
}
let mut data = Vec::new();
for part in value.split(",").map(str::trim) {
let mut iter = part.split(";");
let charset_name = iter.next()?.trim();
let charset = MimeCharset::parse(charset_name)?;
let mut q = None;
loop {
let Some(next) = iter.next().map(str::trim) else {
break;
};
if let Some(raw_q) = next.strip_prefix("q=") {
if q.is_some() {
return None;
}
q = Some(QValue::parse(raw_q)?);
}
}
let q = q.unwrap_or_default();
data.push(AcceptMimeCharset::new(charset, q));
}
Some(data)
}
pub const fn new(charset: MimeCharset, q: QValue) -> Self {
Self { charset, q }
}
pub const fn charset(&self) -> &MimeCharset {
&self.charset
}
pub const fn quality(&self) -> QValue {
self.q
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
pub struct MimeTypeWithCharset {
mime: MimeType,
charset: MimeCharset,
}
impl AsRef<MimeType> for MimeTypeWithCharset {
fn as_ref(&self) -> &MimeType {
&self.mime
}
}
impl MimeTypeWithCharset {
pub const APPLICATION_OCTET_STREAM: MimeTypeWithCharset =
MimeTypeWithCharset::from_mime(MimeType::ApplicationOctetStream);
pub const fn new(mime: MimeType, charset: MimeCharset) -> Self {
Self { mime, charset }
}
pub const fn from_mime(mime: MimeType) -> Self {
Self { mime, charset: MimeCharset::Unspecified }
}
pub fn parse_from_content_type_header(value: impl AsRef<str>) -> Option<Self> {
let mut iter = value.as_ref().split(";");
let ct = iter.next()?;
let mt = MimeType::parse(ct.trim())?;
let charset = loop {
let Some(next) = iter.next().map(str::trim) else { break MimeCharset::Unspecified };
let mut stack_buffer = [0u8; 8];
if !crate::util::ascii_to_lower_first_n(&mut stack_buffer, next).starts_with("charset=") {
continue;
}
break MimeCharset::parse(next.get(8..)?)?;
};
Some(MimeTypeWithCharset::new(mt, charset))
}
pub const fn mime(&self) -> &MimeType {
&self.mime
}
pub const fn charset(&self) -> &MimeCharset {
&self.charset
}
pub const fn has_charset(&self) -> bool {
!matches!(self.charset, MimeCharset::Unspecified)
}
}
impl Display for MimeTypeWithCharset {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if let Some(charset) = self.charset.as_str() {
f.write_fmt(format_args!("{}; charset={}", self.mime.as_str(), charset))
} else {
f.write_str(self.mime.as_str())
}
}
}
impl<T> From<T> for MimeTypeWithCharset
where
T: Into<MimeType>,
{
fn from(value: T) -> Self {
MimeTypeWithCharset::new(value.into(), MimeCharset::Unspecified)
}
}
impl<T, Y> From<(T, Y)> for MimeTypeWithCharset
where
T: Into<MimeType>,
Y: Into<MimeCharset>,
{
fn from(value: (T, Y)) -> Self {
MimeTypeWithCharset::new(value.0.into(), value.1.into())
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum MimeGroup {
Font,
Application,
Image,
Video,
Audio,
Text,
Other(String),
}
impl AsRef<MimeGroup> for MimeGroup {
fn as_ref(&self) -> &MimeGroup {
self
}
}
impl Display for MimeGroup {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
const WELL_KNOWN_GROUPS: &[MimeGroup] = &[
MimeGroup::Font,
MimeGroup::Application,
MimeGroup::Image,
MimeGroup::Video,
MimeGroup::Audio,
MimeGroup::Text,
];
impl MimeGroup {
pub fn parse<T: AsRef<str>>(value: T) -> Option<Self> {
let mut value = value.as_ref();
if let Some((group, _)) = value.split_once("/") {
value = group;
}
for char in value.bytes() {
if !check_header_byte(char) {
return None;
}
}
Some(match value {
"font" => MimeGroup::Font,
"application" => MimeGroup::Application,
"image" => MimeGroup::Image,
"video" => MimeGroup::Video,
"audio" => MimeGroup::Audio,
"text" => MimeGroup::Text,
_ => MimeGroup::Other(value.to_string()),
})
}
#[must_use]
pub const fn well_known() -> &'static [MimeGroup] {
WELL_KNOWN_GROUPS
}
#[must_use]
pub const fn is_well_known(&self) -> bool {
!matches!(self, Self::Other(_))
}
#[must_use]
pub const fn is_custom(&self) -> bool {
matches!(self, Self::Other(_))
}
pub const fn well_known_str(&self) -> Option<&'static str> {
Some(match self {
MimeGroup::Font => "font",
MimeGroup::Application => "application",
MimeGroup::Image => "image",
MimeGroup::Video => "video",
MimeGroup::Audio => "audio",
MimeGroup::Text => "text",
MimeGroup::Other(_) => return None,
})
}
pub fn as_str(&self) -> &str {
match self {
MimeGroup::Font => "font",
MimeGroup::Application => "application",
MimeGroup::Image => "image",
MimeGroup::Video => "video",
MimeGroup::Audio => "audio",
MimeGroup::Text => "text",
MimeGroup::Other(o) => o.as_str(),
}
}
}
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)]
#[non_exhaustive]
pub enum MimeType {
FontTtf,
FontOtf,
FontWoff,
FontWoff2,
ApplicationAbiWord,
ApplicationFreeArc,
ApplicationAmazonEbook,
ApplicationBzip,
ApplicationBzip2,
ApplicationCDAudio,
ApplicationCShell,
ApplicationMicrosoftWord,
ApplicationMicrosoftWordXml,
ApplicationMicrosoftFont,
ApplicationEpub,
ApplicationGzip,
ApplicationJar,
ApplicationJavaClass,
ApplicationOctetStream,
ApplicationJson,
ApplicationJsonLd,
ApplicationYaml,
TextLua,
ApplicationLuaBytecode,
ApplicationPdf,
ApplicationZip,
ApplicationAppleInstallerPackage,
ApplicationAppleMachBinary,
ApplicationOpenDocumentPresentation,
ApplicationOpenDocumentSpreadsheet,
ApplicationOpenDocumentText,
ApplicationOgg,
ApplicationPhp,
ApplicationMicrosoftPowerpoint,
ApplicationMicrosoftPowerpointXml,
ApplicationRar,
ApplicationRichText,
ApplicationBourneShell,
ApplicationTapeArchive,
ApplicationMicrosoftVisio,
ApplicationXHtml,
ApplicationMicrosoftExcel,
ApplicationMicrosoftExcelXml,
ApplicationMicrosoftInstaller,
ApplicationXml,
ApplicationXul,
ApplicationDicom,
Application7Zip,
ApplicationXz,
ApplicationWasm,
ApplicationToml,
ApplicationElf,
ApplicationDosMZExe,
VideoMp4,
VideoOgg,
VideoWebm,
VideoAvi,
VideoMpeg,
VideoMpegTransportStream,
Video3gpp,
Video3gpp2,
ImageBmp,
ImageGif,
ImageJpeg,
ImageAvif,
ImagePng,
ImageQoi,
ImageApng,
ImageWebp,
ImageSvg,
ImageIcon,
ImageTiff,
ImageHeic,
AudioAac,
AudioMidi,
AudioMpeg,
AudioOgg,
AudioWaveform,
AudioWebm,
Audio3gpp,
Audio3gpp2,
AudioMp3,
AudioMp4,
TextCss,
TextHtml,
TextJavaScript,
TextRust,
TextPython,
TextPlain,
TextCsv,
TextCalendar,
Other(MimeGroup, String),
}
impl AsRef<MimeType> for MimeType {
fn as_ref(&self) -> &MimeType {
self
}
}
const WELL_KNOWN_TYPES: &[MimeType] = &[
MimeType::FontTtf,
MimeType::FontOtf,
MimeType::FontWoff,
MimeType::FontWoff2,
MimeType::ApplicationAbiWord,
MimeType::ApplicationFreeArc,
MimeType::ApplicationAmazonEbook,
MimeType::ApplicationBzip,
MimeType::ApplicationBzip2,
MimeType::ApplicationCDAudio,
MimeType::ApplicationCShell,
MimeType::ApplicationMicrosoftWord,
MimeType::ApplicationMicrosoftWordXml,
MimeType::ApplicationMicrosoftFont,
MimeType::ApplicationEpub,
MimeType::ApplicationGzip,
MimeType::ApplicationJar,
MimeType::ApplicationJavaClass,
MimeType::ApplicationOctetStream,
MimeType::ApplicationJson,
MimeType::ApplicationJsonLd,
MimeType::ApplicationPdf,
MimeType::ApplicationZip,
MimeType::ApplicationAppleInstallerPackage,
MimeType::ApplicationAppleMachBinary,
MimeType::ApplicationOpenDocumentPresentation,
MimeType::ApplicationOpenDocumentSpreadsheet,
MimeType::ApplicationOpenDocumentText,
MimeType::ApplicationOgg,
MimeType::ApplicationPhp,
MimeType::ApplicationMicrosoftPowerpoint,
MimeType::ApplicationMicrosoftPowerpointXml,
MimeType::ApplicationRar,
MimeType::ApplicationRichText,
MimeType::ApplicationBourneShell,
MimeType::ApplicationTapeArchive,
MimeType::ApplicationMicrosoftVisio,
MimeType::ApplicationXHtml,
MimeType::ApplicationMicrosoftExcel,
MimeType::ApplicationMicrosoftExcelXml,
MimeType::ApplicationXml,
MimeType::ApplicationXul,
MimeType::ApplicationDicom,
MimeType::Application7Zip,
MimeType::ApplicationWasm,
MimeType::ApplicationToml,
MimeType::ApplicationElf,
MimeType::ApplicationDosMZExe,
MimeType::ApplicationMicrosoftInstaller,
MimeType::VideoMp4,
MimeType::VideoOgg,
MimeType::VideoWebm,
MimeType::VideoAvi,
MimeType::VideoMpeg,
MimeType::VideoMpegTransportStream,
MimeType::Video3gpp,
MimeType::Video3gpp2,
MimeType::ImageBmp,
MimeType::ImageGif,
MimeType::ImageJpeg,
MimeType::ImageAvif,
MimeType::ImagePng,
MimeType::ImageQoi,
MimeType::ImageApng,
MimeType::ImageWebp,
MimeType::ImageSvg,
MimeType::ImageIcon,
MimeType::ImageTiff,
MimeType::ImageHeic,
MimeType::AudioAac,
MimeType::AudioMidi,
MimeType::AudioMpeg,
MimeType::AudioMp3,
MimeType::AudioOgg,
MimeType::AudioWaveform,
MimeType::AudioWebm,
MimeType::Audio3gpp,
MimeType::Audio3gpp2,
MimeType::AudioMp4,
MimeType::TextCss,
MimeType::TextHtml,
MimeType::TextJavaScript,
MimeType::TextRust,
MimeType::TextPython,
MimeType::TextPlain,
MimeType::TextCsv,
MimeType::TextCalendar,
MimeType::ApplicationYaml,
MimeType::TextLua,
MimeType::ApplicationLuaBytecode,
MimeType::ApplicationXz,
];
impl MimeType {
pub const fn with_charset(self, charset: MimeCharset) -> MimeTypeWithCharset {
MimeTypeWithCharset::new(self, charset)
}
pub const fn unspecified_charset(self) -> MimeTypeWithCharset {
MimeTypeWithCharset::new(self, MimeCharset::Unspecified)
}
pub const fn utf8(self) -> MimeTypeWithCharset {
MimeTypeWithCharset::new(self, MimeCharset::Utf8)
}
pub fn from_extension(extension: impl AsRef<str>) -> Self {
let mut stack_buffer = [0u8; 8];
match crate::util::ascii_to_lower_first_n(&mut stack_buffer, extension.as_ref()) {
"css" => MimeType::TextCss,
"html" => MimeType::TextHtml,
"htm" => MimeType::TextHtml,
"js" => MimeType::TextJavaScript,
"mjs" => MimeType::TextJavaScript,
"rs" => MimeType::TextRust,
"py" => MimeType::TextPython,
"txt" => MimeType::TextPlain,
"bmp" => MimeType::ImageBmp,
"gif" => MimeType::ImageGif,
"jpeg" => MimeType::ImageJpeg,
"jpg" => MimeType::ImageJpeg,
"png" => MimeType::ImagePng,
"qoi" => MimeType::ImageQoi,
"webp" => MimeType::ImageWebp,
"svg" => MimeType::ImageSvg,
"ico" => MimeType::ImageIcon,
"json" => MimeType::ApplicationJson,
"pdf" => MimeType::ApplicationPdf,
"zip" => MimeType::ApplicationZip,
"mp4" => MimeType::VideoMp4,
"m4a" => MimeType::AudioMp4,
"ogv" => MimeType::VideoOgg,
"webm" => MimeType::VideoWebm,
"ttf" => MimeType::FontTtf,
"otf" => MimeType::FontOtf,
"woff" => MimeType::FontWoff,
"woff2" => MimeType::FontWoff2,
"abw" => MimeType::ApplicationAbiWord,
"arc" => MimeType::ApplicationFreeArc,
"azw" => MimeType::ApplicationAmazonEbook,
"bz" => MimeType::ApplicationBzip,
"bz2" => MimeType::ApplicationBzip2,
"cda" => MimeType::ApplicationCDAudio,
"csh" => MimeType::ApplicationCShell,
"doc" => MimeType::ApplicationMicrosoftWord,
"docx" => MimeType::ApplicationMicrosoftWordXml,
"eot" => MimeType::ApplicationMicrosoftFont,
"epub" => MimeType::ApplicationEpub,
"gz" => MimeType::ApplicationGzip,
"jar" => MimeType::ApplicationJar,
"class" => MimeType::ApplicationJavaClass,
"bin" => MimeType::ApplicationOctetStream,
"jsonld" => MimeType::ApplicationJsonLd,
"mpkg" => MimeType::ApplicationAppleInstallerPackage,
"dylib" => MimeType::ApplicationAppleMachBinary,
"odp" => MimeType::ApplicationOpenDocumentPresentation,
"ods" => MimeType::ApplicationOpenDocumentSpreadsheet,
"odt" => MimeType::ApplicationOpenDocumentText,
"ogx" => MimeType::ApplicationOgg,
"php" => MimeType::ApplicationPhp,
"ppt" => MimeType::ApplicationMicrosoftPowerpoint,
"pptx" => MimeType::ApplicationMicrosoftPowerpointXml,
"rar" => MimeType::ApplicationRar,
"rtf" => MimeType::ApplicationRichText,
"sh" => MimeType::ApplicationBourneShell,
"tar" => MimeType::ApplicationTapeArchive,
"vsd" => MimeType::ApplicationMicrosoftVisio,
"xhtml" => MimeType::ApplicationXHtml,
"xls" => MimeType::ApplicationMicrosoftExcel,
"xlsx" => MimeType::ApplicationMicrosoftExcelXml,
"xml" => MimeType::ApplicationXml,
"xul" => MimeType::ApplicationXul,
"dcm" => MimeType::ApplicationDicom,
"7z" => MimeType::Application7Zip,
"wasm" => MimeType::ApplicationWasm,
"avi" => MimeType::VideoAvi,
"mpeg" => MimeType::VideoMpeg,
"ts" => MimeType::VideoMpegTransportStream,
"3gp" => MimeType::Video3gpp,
"3g2" => MimeType::Video3gpp2,
"avif" => MimeType::ImageAvif,
"apng" => MimeType::ImageApng,
"tif" => MimeType::ImageTiff,
"aac" => MimeType::AudioAac,
"mid" => MimeType::AudioMidi,
"mp2" => MimeType::AudioMpeg,
"mpa" => MimeType::AudioMpeg,
"mp2a" => MimeType::AudioMpeg,
"m2a" => MimeType::AudioMpeg,
"mp3" => MimeType::AudioMp3,
"oga" => MimeType::AudioOgg,
"wav" => MimeType::AudioWaveform,
"weba" => MimeType::AudioWebm,
"csv" => MimeType::TextCsv,
"cal" => MimeType::TextCalendar,
"yaml" | "yml" => MimeType::ApplicationYaml,
"lua" => MimeType::TextLua,
"luac" => MimeType::ApplicationLuaBytecode,
"xz" => MimeType::ApplicationXz,
"toml" => MimeType::ApplicationToml,
"so" => MimeType::ApplicationElf,
"o" => MimeType::ApplicationElf,
"ko" => MimeType::ApplicationElf,
"exe" => MimeType::ApplicationDosMZExe,
"com" => MimeType::ApplicationDosMZExe,
"dll" => MimeType::ApplicationDosMZExe,
"sys" => MimeType::ApplicationDosMZExe,
"heic" => MimeType::ImageHeic,
"msi" => MimeType::ApplicationMicrosoftInstaller,
_ => MimeType::ApplicationOctetStream,
}
}
pub fn from_file_header(data: impl AsRef<[u8]>) -> &'static [Self] {
crate::file_typeifier::typeify_header(data.as_ref())
}
#[must_use]
pub const fn extension(&self) -> &'static str {
match self {
MimeType::FontTtf => "ttf",
MimeType::FontOtf => "otf",
MimeType::FontWoff => "woff",
MimeType::FontWoff2 => "woff2",
MimeType::ApplicationAbiWord => "abw",
MimeType::ApplicationFreeArc => "arc",
MimeType::ApplicationAmazonEbook => "azw",
MimeType::ApplicationBzip => "bz",
MimeType::ApplicationBzip2 => "bz2",
MimeType::ApplicationCDAudio => "cda",
MimeType::ApplicationCShell => "csh",
MimeType::ApplicationMicrosoftWord => "doc",
MimeType::ApplicationMicrosoftWordXml => "docx",
MimeType::ApplicationMicrosoftFont => "eot",
MimeType::ApplicationMicrosoftInstaller => "msi",
MimeType::ApplicationEpub => "epub",
MimeType::ApplicationGzip => "gz",
MimeType::ApplicationJar => "jar",
MimeType::ApplicationJavaClass => "class",
MimeType::ApplicationOctetStream => "bin",
MimeType::ApplicationJson => "json",
MimeType::ApplicationJsonLd => "jsonld",
MimeType::ApplicationPdf => "pdf",
MimeType::ApplicationZip => "zip",
MimeType::ApplicationAppleInstallerPackage => "mpkg",
MimeType::ApplicationAppleMachBinary => "dylib",
MimeType::ApplicationOpenDocumentPresentation => "odp",
MimeType::ApplicationOpenDocumentSpreadsheet => "ods",
MimeType::ApplicationOpenDocumentText => "odt",
MimeType::ApplicationOgg => "ogx",
MimeType::ApplicationPhp => "php",
MimeType::ApplicationMicrosoftPowerpoint => "ppt",
MimeType::ApplicationMicrosoftPowerpointXml => "pptx",
MimeType::ApplicationRar => "rar",
MimeType::ApplicationRichText => "rtf",
MimeType::ApplicationBourneShell => "sh",
MimeType::ApplicationTapeArchive => "tar",
MimeType::ApplicationMicrosoftVisio => "vsd",
MimeType::ApplicationXHtml => "xhtml",
MimeType::ApplicationMicrosoftExcel => "xls",
MimeType::ApplicationMicrosoftExcelXml => "xlsx",
MimeType::ApplicationXml => "xml",
MimeType::ApplicationXul => "xul",
MimeType::ApplicationDicom => "dcm",
MimeType::Application7Zip => "7z",
MimeType::ApplicationWasm => "wasm",
MimeType::VideoMp4 => "mp4",
MimeType::VideoOgg => "ogv",
MimeType::VideoWebm => "webm",
MimeType::VideoAvi => "avi",
MimeType::VideoMpeg => "mpeg",
MimeType::VideoMpegTransportStream => "ts",
MimeType::Video3gpp => "3gp",
MimeType::Video3gpp2 => "3g2",
MimeType::ImageBmp => "bmp",
MimeType::ImageGif => "gif",
MimeType::ImageJpeg => "jpg",
MimeType::ImageAvif => "avif",
MimeType::ImagePng => "png",
MimeType::ImageQoi => "qoi",
MimeType::ImageApng => "apng",
MimeType::ImageWebp => "webp",
MimeType::ImageSvg => "svg",
MimeType::ImageIcon => "ico",
MimeType::ImageTiff => "tif",
MimeType::ImageHeic => "heic",
MimeType::AudioAac => "aac",
MimeType::AudioMidi => "mid",
MimeType::AudioMpeg => "mp2",
MimeType::AudioOgg => "oga",
MimeType::AudioWaveform => "wav",
MimeType::AudioWebm => "weba",
MimeType::Audio3gpp => "3gp",
MimeType::Audio3gpp2 => "3g2",
MimeType::AudioMp4 => "m4a",
MimeType::AudioMp3 => "mp3",
MimeType::TextCss => "css",
MimeType::TextHtml => "html",
MimeType::TextJavaScript => "js",
MimeType::TextRust => "rs",
MimeType::TextPython => "py",
MimeType::TextPlain => "txt",
MimeType::TextCsv => "csv",
MimeType::TextCalendar => "cal",
MimeType::ApplicationYaml => "yaml",
MimeType::TextLua => "lua",
MimeType::ApplicationLuaBytecode => "luac",
MimeType::ApplicationXz => "xz",
MimeType::Other(_, _) => "bin",
MimeType::ApplicationToml => "toml",
MimeType::ApplicationElf => "o",
MimeType::ApplicationDosMZExe => "exe",
}
}
pub const fn mime_group(&self) -> &MimeGroup {
match self {
MimeType::FontTtf => &MimeGroup::Font,
MimeType::FontOtf => &MimeGroup::Font,
MimeType::FontWoff => &MimeGroup::Font,
MimeType::FontWoff2 => &MimeGroup::Font,
MimeType::ApplicationAbiWord => &MimeGroup::Application,
MimeType::ApplicationFreeArc => &MimeGroup::Application,
MimeType::ApplicationAmazonEbook => &MimeGroup::Application,
MimeType::ApplicationBzip => &MimeGroup::Application,
MimeType::ApplicationBzip2 => &MimeGroup::Application,
MimeType::ApplicationCDAudio => &MimeGroup::Application,
MimeType::ApplicationCShell => &MimeGroup::Application,
MimeType::ApplicationMicrosoftWord => &MimeGroup::Application,
MimeType::ApplicationMicrosoftWordXml => &MimeGroup::Application,
MimeType::ApplicationMicrosoftInstaller => &MimeGroup::Application,
MimeType::ApplicationMicrosoftFont => &MimeGroup::Application,
MimeType::ApplicationEpub => &MimeGroup::Application,
MimeType::ApplicationGzip => &MimeGroup::Application,
MimeType::ApplicationJar => &MimeGroup::Application,
MimeType::ApplicationJavaClass => &MimeGroup::Application,
MimeType::ApplicationOctetStream => &MimeGroup::Application,
MimeType::ApplicationJson => &MimeGroup::Application,
MimeType::ApplicationJsonLd => &MimeGroup::Application,
MimeType::ApplicationYaml => &MimeGroup::Application,
MimeType::ApplicationLuaBytecode => &MimeGroup::Application,
MimeType::ApplicationPdf => &MimeGroup::Application,
MimeType::ApplicationZip => &MimeGroup::Application,
MimeType::ApplicationAppleInstallerPackage => &MimeGroup::Application,
MimeType::ApplicationAppleMachBinary => &MimeGroup::Application,
MimeType::ApplicationOpenDocumentPresentation => &MimeGroup::Application,
MimeType::ApplicationOpenDocumentSpreadsheet => &MimeGroup::Application,
MimeType::ApplicationOpenDocumentText => &MimeGroup::Application,
MimeType::ApplicationOgg => &MimeGroup::Application,
MimeType::ApplicationPhp => &MimeGroup::Application,
MimeType::ApplicationMicrosoftPowerpoint => &MimeGroup::Application,
MimeType::ApplicationMicrosoftPowerpointXml => &MimeGroup::Application,
MimeType::ApplicationRar => &MimeGroup::Application,
MimeType::ApplicationRichText => &MimeGroup::Application,
MimeType::ApplicationBourneShell => &MimeGroup::Application,
MimeType::ApplicationTapeArchive => &MimeGroup::Application,
MimeType::ApplicationMicrosoftVisio => &MimeGroup::Application,
MimeType::ApplicationXHtml => &MimeGroup::Application,
MimeType::ApplicationMicrosoftExcel => &MimeGroup::Application,
MimeType::ApplicationMicrosoftExcelXml => &MimeGroup::Application,
MimeType::ApplicationXml => &MimeGroup::Application,
MimeType::ApplicationXul => &MimeGroup::Application,
MimeType::ApplicationDicom => &MimeGroup::Application,
MimeType::Application7Zip => &MimeGroup::Application,
MimeType::ApplicationXz => &MimeGroup::Application,
MimeType::ApplicationWasm => &MimeGroup::Application,
MimeType::ApplicationToml => &MimeGroup::Application,
MimeType::ApplicationElf => &MimeGroup::Application,
MimeType::ApplicationDosMZExe => &MimeGroup::Application,
MimeType::VideoMp4 => &MimeGroup::Video,
MimeType::VideoOgg => &MimeGroup::Video,
MimeType::VideoWebm => &MimeGroup::Video,
MimeType::VideoAvi => &MimeGroup::Video,
MimeType::VideoMpeg => &MimeGroup::Video,
MimeType::VideoMpegTransportStream => &MimeGroup::Video,
MimeType::Video3gpp => &MimeGroup::Video,
MimeType::Video3gpp2 => &MimeGroup::Video,
MimeType::ImageBmp => &MimeGroup::Image,
MimeType::ImageGif => &MimeGroup::Image,
MimeType::ImageJpeg => &MimeGroup::Image,
MimeType::ImageAvif => &MimeGroup::Image,
MimeType::ImagePng => &MimeGroup::Image,
MimeType::ImageQoi => &MimeGroup::Image,
MimeType::ImageApng => &MimeGroup::Image,
MimeType::ImageWebp => &MimeGroup::Image,
MimeType::ImageSvg => &MimeGroup::Image,
MimeType::ImageIcon => &MimeGroup::Image,
MimeType::ImageTiff => &MimeGroup::Image,
MimeType::ImageHeic => &MimeGroup::Image,
MimeType::AudioAac => &MimeGroup::Audio,
MimeType::AudioMidi => &MimeGroup::Audio,
MimeType::AudioMpeg => &MimeGroup::Audio,
MimeType::AudioOgg => &MimeGroup::Audio,
MimeType::AudioWaveform => &MimeGroup::Audio,
MimeType::AudioWebm => &MimeGroup::Audio,
MimeType::Audio3gpp => &MimeGroup::Audio,
MimeType::Audio3gpp2 => &MimeGroup::Audio,
MimeType::AudioMp4 => &MimeGroup::Audio,
MimeType::AudioMp3 => &MimeGroup::Audio,
MimeType::TextCss => &MimeGroup::Text,
MimeType::TextHtml => &MimeGroup::Text,
MimeType::TextJavaScript => &MimeGroup::Text,
MimeType::TextRust => &MimeGroup::Text,
MimeType::TextPython => &MimeGroup::Text,
MimeType::TextLua => &MimeGroup::Text,
MimeType::TextPlain => &MimeGroup::Text,
MimeType::TextCsv => &MimeGroup::Text,
MimeType::TextCalendar => &MimeGroup::Text,
MimeType::Other(group, _) => group,
}
}
pub const fn has_unique_known_extension(&self) -> bool {
match self {
MimeType::Video3gpp2 | MimeType::Audio3gpp2 => false, MimeType::Video3gpp | MimeType::Audio3gpp => false, MimeType::AudioMp4 | MimeType::VideoMp4 | MimeType::AudioAac => false, MimeType::AudioMpeg | MimeType::VideoMpeg => false, MimeType::Other(_, _) => false, _ => true,
}
}
#[must_use]
pub const fn well_known() -> &'static [MimeType] {
WELL_KNOWN_TYPES
}
#[must_use]
pub const fn is_well_known(&self) -> bool {
!matches!(self, MimeType::Other(_, _))
}
#[must_use]
pub const fn is_custom(&self) -> bool {
matches!(self, Self::Other(_, _))
}
pub const fn well_known_str(&self) -> Option<&'static str> {
Some(match self {
MimeType::TextCss => "text/css",
MimeType::TextHtml => "text/html",
MimeType::TextJavaScript => "text/javascript",
MimeType::TextRust => "text/rust",
MimeType::TextPython => "text/x-python",
MimeType::TextPlain => "text/plain",
MimeType::ImageBmp => "image/bmp",
MimeType::ImageGif => "image/gif",
MimeType::ImageJpeg => "image/jpeg",
MimeType::ImagePng => "image/png",
MimeType::ImageQoi => "image/qoi",
MimeType::ImageWebp => "image/webp",
MimeType::ImageSvg => "image/svg+xml",
MimeType::ImageIcon => "image/vnd.microsoft.icon",
MimeType::ApplicationOctetStream => "application/octet-stream",
MimeType::ApplicationJson => "application/json",
MimeType::ApplicationPdf => "application/pdf",
MimeType::ApplicationZip => "application/zip",
MimeType::VideoMp4 => "video/mp4",
MimeType::VideoOgg => "video/ogg",
MimeType::VideoWebm => "video/webm",
MimeType::FontTtf => "font/ttf",
MimeType::FontOtf => "font/otf",
MimeType::FontWoff => "font/woff",
MimeType::FontWoff2 => "font/woff2",
MimeType::ApplicationAbiWord => "application/x-abiword",
MimeType::ApplicationFreeArc => "application/x-freearc",
MimeType::ApplicationAmazonEbook => "application/vnd.amazon.ebook",
MimeType::ApplicationBzip => "application/x-bzip",
MimeType::ApplicationBzip2 => "application/x-bzip2",
MimeType::ApplicationCDAudio => "application/x-cdf",
MimeType::ApplicationCShell => "application/x-csh",
MimeType::ApplicationMicrosoftWord => "application/msword",
MimeType::ApplicationMicrosoftWordXml => {
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}
MimeType::ApplicationMicrosoftInstaller => "application/x-ms-installer",
MimeType::ApplicationMicrosoftFont => "application/vnd.ms-fontobject",
MimeType::ApplicationEpub => "application/epub+zip",
MimeType::ApplicationGzip => "application/gzip",
MimeType::ApplicationJar => "application/java-archive",
MimeType::ApplicationJavaClass => "application/x-java-class",
MimeType::ApplicationJsonLd => "application/ld+json",
MimeType::ApplicationAppleInstallerPackage => "application/vnd.apple.installer+xml",
MimeType::ApplicationAppleMachBinary => "application/x-mach-binary",
MimeType::ApplicationOpenDocumentPresentation => {
"application/vnd.oasis.opendocument.presentation"
}
MimeType::ApplicationOpenDocumentSpreadsheet => {
"application/vnd.oasis.opendocument.spreadsheet"
}
MimeType::ApplicationOpenDocumentText => "application/vnd.oasis.opendocument.text",
MimeType::ApplicationOgg => "application/ogg",
MimeType::ApplicationPhp => "application/x-httpd-php",
MimeType::ApplicationMicrosoftPowerpoint => "application/vnd.ms-powerpoint",
MimeType::ApplicationMicrosoftPowerpointXml => {
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
}
MimeType::ApplicationRar => "application/vnd.rar",
MimeType::ApplicationRichText => "application/rtf",
MimeType::ApplicationBourneShell => "application/x-sh",
MimeType::ApplicationTapeArchive => "application/x-tar",
MimeType::ApplicationMicrosoftVisio => "application/vnd.visio",
MimeType::ApplicationXHtml => "application/xhtml+xml",
MimeType::ApplicationMicrosoftExcel => "application/vnd.ms-excel",
MimeType::ApplicationMicrosoftExcelXml => {
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
MimeType::ApplicationXml => "application/xml",
MimeType::ApplicationXul => "application/vnd.mozilla.xul+xml",
MimeType::ApplicationDicom => "application/dicom",
MimeType::Application7Zip => "application/x-7z-compressed",
MimeType::ApplicationWasm => "application/wasm",
MimeType::ApplicationToml => "application/toml",
MimeType::ApplicationElf => "application/x-elf",
MimeType::ApplicationDosMZExe => "application/x-msdownload",
MimeType::VideoAvi => "video/x-msvideo",
MimeType::VideoMpeg => "video/mpeg",
MimeType::VideoMpegTransportStream => "video/mp2t",
MimeType::Video3gpp => "video/3gpp",
MimeType::Video3gpp2 => "video/3gpp2",
MimeType::ImageAvif => "image/avif",
MimeType::ImageApng => "image/apng",
MimeType::ImageTiff => "image/tiff",
MimeType::ImageHeic => "image/heic",
MimeType::AudioAac => "audio/aac",
MimeType::AudioMidi => "audio/midi",
MimeType::AudioMpeg => "audio/mpa",
MimeType::AudioOgg => "audio/ogg",
MimeType::AudioWaveform => "audio/wav",
MimeType::AudioWebm => "audio/webm",
MimeType::Audio3gpp => "audio/3gpp",
MimeType::Audio3gpp2 => "audio/3gpp2",
MimeType::AudioMp4 => "audio/mp4",
MimeType::AudioMp3 => "audio/mpeg",
MimeType::TextCsv => "text/csv",
MimeType::TextCalendar => "text/calendar",
MimeType::ApplicationYaml => "application/yaml",
MimeType::TextLua => "text/x-lua",
MimeType::ApplicationLuaBytecode => "application/x-lua-bytecode",
MimeType::ApplicationXz => "application/x-xz",
MimeType::Other(_, _) => return None,
})
}
pub fn as_str(&self) -> &str {
match self {
MimeType::TextCss => "text/css",
MimeType::TextHtml => "text/html",
MimeType::TextJavaScript => "text/javascript",
MimeType::TextRust => "text/rust",
MimeType::TextPython => "text/x-python",
MimeType::TextPlain => "text/plain",
MimeType::ImageBmp => "image/bmp",
MimeType::ImageGif => "image/gif",
MimeType::ImageJpeg => "image/jpeg",
MimeType::ImagePng => "image/png",
MimeType::ImageQoi => "image/qoi",
MimeType::ImageWebp => "image/webp",
MimeType::ImageSvg => "image/svg+xml",
MimeType::ImageIcon => "image/vnd.microsoft.icon",
MimeType::ApplicationOctetStream => "application/octet-stream",
MimeType::ApplicationJson => "application/json",
MimeType::ApplicationPdf => "application/pdf",
MimeType::ApplicationZip => "application/zip",
MimeType::VideoMp4 => "video/mp4",
MimeType::VideoOgg => "video/ogg",
MimeType::VideoWebm => "video/webm",
MimeType::FontTtf => "font/ttf",
MimeType::FontOtf => "font/otf",
MimeType::FontWoff => "font/woff",
MimeType::FontWoff2 => "font/woff2",
MimeType::ApplicationAbiWord => "application/x-abiword",
MimeType::ApplicationFreeArc => "application/x-freearc",
MimeType::ApplicationAmazonEbook => "application/vnd.amazon.ebook",
MimeType::ApplicationBzip => "application/x-bzip",
MimeType::ApplicationBzip2 => "application/x-bzip2",
MimeType::ApplicationCDAudio => "application/x-cdf",
MimeType::ApplicationCShell => "application/x-csh",
MimeType::ApplicationMicrosoftWord => "application/msword",
MimeType::ApplicationMicrosoftWordXml => {
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
}
MimeType::ApplicationMicrosoftInstaller => "application/x-ms-installer",
MimeType::ApplicationMicrosoftFont => "application/vnd.ms-fontobject",
MimeType::ApplicationEpub => "application/epub+zip",
MimeType::ApplicationGzip => "application/gzip",
MimeType::ApplicationJar => "application/java-archive",
MimeType::ApplicationJavaClass => "application/x-java-class",
MimeType::ApplicationJsonLd => "application/ld+json",
MimeType::ApplicationAppleInstallerPackage => "application/vnd.apple.installer+xml",
MimeType::ApplicationAppleMachBinary => "application/x-mach-binary",
MimeType::ApplicationOpenDocumentPresentation => {
"application/vnd.oasis.opendocument.presentation"
}
MimeType::ApplicationOpenDocumentSpreadsheet => {
"application/vnd.oasis.opendocument.spreadsheet"
}
MimeType::ApplicationOpenDocumentText => "application/vnd.oasis.opendocument.text",
MimeType::ApplicationOgg => "application/ogg",
MimeType::ApplicationPhp => "application/x-httpd-php",
MimeType::ApplicationMicrosoftPowerpoint => "application/vnd.ms-powerpoint",
MimeType::ApplicationMicrosoftPowerpointXml => {
"application/vnd.openxmlformats-officedocument.presentationml.presentation"
}
MimeType::ApplicationRar => "application/vnd.rar",
MimeType::ApplicationRichText => "application/rtf",
MimeType::ApplicationBourneShell => "application/x-sh",
MimeType::ApplicationTapeArchive => "application/x-tar",
MimeType::ApplicationMicrosoftVisio => "application/vnd.visio",
MimeType::ApplicationXHtml => "application/xhtml+xml",
MimeType::ApplicationMicrosoftExcel => "application/vnd.ms-excel",
MimeType::ApplicationMicrosoftExcelXml => {
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
MimeType::ApplicationXml => "application/xml",
MimeType::ApplicationXul => "application/vnd.mozilla.xul+xml",
MimeType::ApplicationDicom => "application/dicom",
MimeType::Application7Zip => "application/x-7z-compressed",
MimeType::ApplicationWasm => "application/wasm",
MimeType::ApplicationToml => "application/toml",
MimeType::ApplicationElf => "application/x-elf",
MimeType::ApplicationDosMZExe => "application/x-msdownload",
MimeType::VideoAvi => "video/x-msvideo",
MimeType::VideoMpeg => "video/mpeg",
MimeType::VideoMpegTransportStream => "video/mp2t",
MimeType::Video3gpp => "video/3gpp",
MimeType::Video3gpp2 => "video/3gpp2",
MimeType::ImageAvif => "image/avif",
MimeType::ImageApng => "image/apng",
MimeType::ImageTiff => "image/tiff",
MimeType::ImageHeic => "image/heic",
MimeType::AudioAac => "audio/aac",
MimeType::AudioMidi => "audio/midi",
MimeType::AudioMpeg => "audio/mpa",
MimeType::AudioOgg => "audio/ogg",
MimeType::AudioWaveform => "audio/wav",
MimeType::AudioWebm => "audio/webm",
MimeType::Audio3gpp => "audio/3gpp",
MimeType::Audio3gpp2 => "audio/3gpp2",
MimeType::AudioMp4 => "audio/mp4",
MimeType::AudioMp3 => "audio/mpeg",
MimeType::TextCsv => "text/csv",
MimeType::TextCalendar => "text/calendar",
MimeType::ApplicationYaml => "application/yaml",
MimeType::TextLua => "text/x-lua",
MimeType::ApplicationLuaBytecode => "application/x-lua-bytecode",
MimeType::ApplicationXz => "application/x-xz",
MimeType::Other(_, data) => data.as_str(),
}
}
pub const fn into_accept(self, q: QValue, mime_charset: MimeCharset) -> AcceptQualityMimeType {
AcceptQualityMimeType::from_mime(self, q, mime_charset)
}
pub fn parse<T: AsRef<str>>(value: T) -> Option<Self> {
Some(match value.as_ref() {
"text/css" => MimeType::TextCss,
"text/html" => MimeType::TextHtml,
"text/javascript" => MimeType::TextJavaScript,
"text/rust" => MimeType::TextRust,
"text/x-rust" => MimeType::TextRust,
"text/x-python" => MimeType::TextPython,
"text/python" => MimeType::TextPython,
"text/plain" => MimeType::TextPlain,
"image/bmp" => MimeType::ImageBmp,
"image/gif" => MimeType::ImageGif,
"image/jpeg" => MimeType::ImageJpeg,
"image/png" => MimeType::ImagePng,
"image/qoi" => MimeType::ImageQoi,
"image/webp" => MimeType::ImageWebp,
"image/svg+xml" => MimeType::ImageSvg,
"image/vnd.microsoft.icon" => MimeType::ImageIcon,
"application/octet-stream" => MimeType::ApplicationOctetStream,
"application/json" => MimeType::ApplicationJson,
"application/pdf" => MimeType::ApplicationPdf,
"application/zip" => MimeType::ApplicationZip,
"video/mp4" => MimeType::VideoMp4,
"video/ogg" => MimeType::VideoOgg,
"video/webm" => MimeType::VideoWebm,
"font/ttf" => MimeType::FontTtf,
"font/otf" => MimeType::FontOtf,
"font/woff" => MimeType::FontWoff,
"font/woff2" => MimeType::FontWoff2,
"application/x-abiword" => MimeType::ApplicationAbiWord,
"application/x-freearc" => MimeType::ApplicationFreeArc,
"application/vnd.amazon.ebook" => MimeType::ApplicationAmazonEbook,
"application/x-bzip" => MimeType::ApplicationBzip,
"application/x-bzip2" => MimeType::ApplicationBzip2,
"application/x-cdf" => MimeType::ApplicationCDAudio,
"application/x-csh" => MimeType::ApplicationCShell,
"application/msword" => MimeType::ApplicationMicrosoftWord,
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" => {
MimeType::ApplicationMicrosoftWordXml
}
"application/x-ms-installer" => MimeType::ApplicationMicrosoftInstaller,
"application/x-msi" => MimeType::ApplicationMicrosoftInstaller,
"application/x-windows-installer" => MimeType::ApplicationMicrosoftInstaller,
"application/vnd.ms-fontobject" => MimeType::ApplicationMicrosoftFont,
"application/epub+zip" => MimeType::ApplicationEpub,
"application/gzip" => MimeType::ApplicationGzip,
"application/java-archive" => MimeType::ApplicationJar,
"application/x-java-class" => MimeType::ApplicationJavaClass,
"application/ld+json" => MimeType::ApplicationJsonLd,
"application/vnd.apple.installer+xml" => MimeType::ApplicationAppleInstallerPackage,
"application/x-mach-binary" => MimeType::ApplicationAppleMachBinary,
"application/vnd.oasis.opendocument.presentation" => {
MimeType::ApplicationOpenDocumentPresentation
}
"application/vnd.oasis.opendocument.spreadsheet" => {
MimeType::ApplicationOpenDocumentSpreadsheet
}
"application/vnd.oasis.opendocument.text" => MimeType::ApplicationOpenDocumentText,
"application/ogg" => MimeType::ApplicationOgg,
"application/x-httpd-php" => MimeType::ApplicationPhp,
"application/vnd.ms-powerpoint" => MimeType::ApplicationMicrosoftPowerpoint,
"application/vnd.openxmlformats-officedocument.presentationml.presentation" => {
MimeType::ApplicationMicrosoftPowerpointXml
}
"application/vnd.rar" => MimeType::ApplicationRar,
"application/rtf" => MimeType::ApplicationRichText,
"application/x-sh" => MimeType::ApplicationBourneShell,
"application/x-tar" => MimeType::ApplicationTapeArchive,
"application/vnd.visio" => MimeType::ApplicationMicrosoftVisio,
"application/xhtml+xml" => MimeType::ApplicationXHtml,
"application/vnd.ms-excel" => MimeType::ApplicationMicrosoftExcel,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" => {
MimeType::ApplicationMicrosoftExcelXml
}
"application/xml" => MimeType::ApplicationXml,
"application/vnd.mozilla.xul+xml" => MimeType::ApplicationXul,
"application/dicom" => MimeType::ApplicationDicom,
"application/x-7z-compressed" => MimeType::Application7Zip,
"application/wasm" => MimeType::ApplicationWasm,
"application/toml" => MimeType::ApplicationToml,
"application/x-elf" => MimeType::ApplicationElf,
"application/x-msdownload"
| "application/exe"
| "application/x-exe"
| "application/win32-exe" => MimeType::ApplicationDosMZExe,
"video/x-msvideo" => MimeType::VideoAvi,
"video/mpeg" => MimeType::VideoMpeg,
"video/mp2t" => MimeType::VideoMpegTransportStream,
"video/3gpp" => MimeType::Video3gpp,
"video/3gpp2" => MimeType::Video3gpp2,
"audio/3gpp" => MimeType::Audio3gpp,
"audio/3gpp2" => MimeType::Audio3gpp2,
"audio/mp4" => MimeType::AudioMp4,
"audio/mpeg" => MimeType::AudioMp3,
"image/avif" => MimeType::ImageAvif,
"image/apng" => MimeType::ImageApng,
"image/tiff" => MimeType::ImageTiff,
"image/heic" => MimeType::ImageHeic,
"audio/aac" => MimeType::AudioAac,
"audio/midi" => MimeType::AudioMidi,
"audio/mpa" => MimeType::AudioMpeg,
"audio/ogg" => MimeType::AudioOgg,
"audio/wav" => MimeType::AudioWaveform,
"audio/webm" => MimeType::AudioWebm,
"text/csv" => MimeType::TextCsv,
"text/calendar" => MimeType::TextCalendar,
"application/yaml" => MimeType::ApplicationYaml,
"text/x-lua" => MimeType::TextLua,
"application/x-lua-bytecode" => MimeType::ApplicationLuaBytecode,
"application/x-xz" => MimeType::ApplicationXz,
other => {
if other.starts_with('/') || other.ends_with('/') {
return None;
}
let mut found_slash = false;
for char in other.bytes() {
if char == b'/' {
if found_slash {
return None;
}
found_slash = true;
continue;
}
if !check_header_byte(char) {
return None;
}
}
if !found_slash {
return None;
}
if let Some(grp) = MimeGroup::parse(other) {
MimeType::Other(grp, other.to_string())
} else {
crate::util::unreachable()
}
}
})
}
}
impl Display for MimeType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
const fn check_header_byte(char: u8) -> bool {
if char <= 31 {
return false;
}
if char & 0b1000_0000 != 0 {
return false;
}
if char.is_ascii_uppercase() {
return false;
}
!matches!(
char,
b'*'
| b'('
| b')'
| b':'
| b'<'
| b'>'
| b'?'
| b'@'
| b'['
| b']'
| b'\\'
| b'{'
| b'}'
| 0x7F
)
}
impl From<MimeType> for AcceptMimeType {
fn from(value: MimeType) -> Self {
AcceptMimeType::Specific(value)
}
}
impl From<&MimeType> for AcceptMimeType {
fn from(value: &MimeType) -> Self {
AcceptMimeType::Specific(value.clone())
}
}
impl From<MimeGroup> for AcceptMimeType {
fn from(value: MimeGroup) -> Self {
AcceptMimeType::GroupWildcard(value)
}
}
impl From<&MimeGroup> for AcceptMimeType {
fn from(value: &MimeGroup) -> Self {
AcceptMimeType::GroupWildcard(value.clone())
}
}
impl From<MimeType> for MimeGroup {
fn from(value: MimeType) -> Self {
value.mime_group().clone()
}
}
impl From<&MimeType> for MimeGroup {
fn from(value: &MimeType) -> Self {
value.mime_group().clone()
}
}
impl From<AcceptQualityMimeType> for AcceptMimeType {
fn from(value: AcceptQualityMimeType) -> Self {
value.value
}
}
#[cfg(test)]
mod tests {
use crate::http::mime::QValue;
#[macro_export]
macro_rules! test_qvalue {
($input:expr, $expected:expr) => {
let q = QValue($input);
assert_eq!(q.as_str(), $expected);
};
}
#[test]
fn constutil() {
test_qvalue!(0, "0.0");
test_qvalue!(1, "0.001");
test_qvalue!(10, "0.01");
test_qvalue!(999, "0.999");
test_qvalue!(1000, "1.0");
}
}