1use core::str;
14use std::{borrow::Cow, fmt::Display, path::Path};
15
16#[derive(Debug)]
21pub struct Mime<'a>(Cow<'a, str>, Cow<'a, str>);
22
23type Result<T> = std::result::Result<T, &'static str>;
24
25impl<'a> Mime<'a> {
26 pub fn new(text: impl Into<Cow<'a, str>>) -> Result<Self> {
61 match text.into() {
62 Cow::Owned(own) => {
63 let mut text = own.split('/');
64 let major = text.next().ok_or("Malformatted mime type")?.to_owned();
65 let minor = text.next().ok_or("Malformatted mime type")?.to_owned();
66 Ok(Mime(major.into(), minor.into()))
67 }
68 Cow::Borrowed(borr) => {
69 let mut text = borr.split('/');
70 let major = text.next().ok_or("Malformatted mime type")?;
71 let minor = text.next().ok_or("Malformatted mime type")?;
72 Ok(Mime(major.into(), minor.into()))
73 }
74 }
75 }
76 pub fn from_filename(filename: &'a str) -> Result<Self> {
89 let ext = match Path::new(filename).extension() {
90 Some(ext) => ext.to_str().ok_or("Error convertion OsString to str")?,
91 None => "",
92 };
93 let major = match ext {
94 "abw" => "application/x-abiword",
95 "arc" => "application/x-freearc",
96 "avi" => "video/x-msvideo",
97 "azw" => "application/vnd.amazon.ebook",
98 "bin" => "application/octet-stream",
99 "bz" => "application/x-bzip",
100 "bz2" => "application/x-bzip2",
101 "cda" => "application/x-cdf",
102 "csh" => "application/x-csh",
103 "doc" => "application/msword",
104 "docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
105 "eot" => "application/vnd.ms-fontobject",
106 "epub" => "application/epub+zip",
107 "gz" => "application/gzip",
108 "ico" => "image/vnd.microsoft.icon",
109 "ics" => "text/calendar",
110 "jar" => "application/java-archive",
111 "js" => "text/javascript",
112 "jsonld" => "application/ld+json",
113 "mid" | "midi" => "audio/x-midi",
114 "mjs" => "text/javascript",
115 "mp3" => "audio/mpeg",
116 "mpkg" => "application/vnd.apple.installer+xml",
117 "odp" => "application/vnd.oasis.opendocument.presentation",
118 "ods" => "application/vnd.oasis.opendocument.spreadsheet",
119 "odt" => "application/vnd.oasis.opendocument.text",
120 "oga" | "ogv" => "audio/ogg",
121 "ogx" => "application/ogg",
122 "php" => "application/x-httpd-php",
123 "ppt" => "application/vnd.ms-powerpoint",
124 "pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
125 "rar" => "application/vnd.rar",
126 "sh" => "application/x-sh",
127 "sgv" => "image/svg+xml",
128 "tar" => "application/x-tar",
129 "tif" | "tiff" => "image/tiff",
130 "ts" => "video/mp2t",
131 "vsd" => "application/vnd.visio",
132 "weba" => "audio/webm",
133 "xhtml" => "application/xhtml+xml",
134 "xls" => "application/vnd.ms-excel",
135 "xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
136 "xul" => "application/vnd.mozilla.xul+xml",
137 "3gp" => "video/3gpp",
138 "3g2" => "video/3gpp2",
139 "7z" => "application/x-7z-compressed",
140 "apng" | "avif" | "bmp" | "gif" | "jpeg" | "png" | "webp" => "image",
141 "jpg" => "image/jpeg",
142 "html" | "htm" | "css" | "csv" => "text",
143 "otf" | "ttf" | "woff" | "woff2" => "font",
144 "json" | "rtf" | "xml" | "zip" => "application",
145 "aac" | "opus" | "wav" | "flac" => "audio",
146 "mp4" | "mpeg" | "webm" | "mkv" => "video",
147 "" | "txt" => "text/plain",
148 _ => return Err("Unknown extension"),
149 };
150 Ok(if major.contains('/') {
151 Mime::new(major)?
152 } else {
153 Mime(major.into(), ext.into())
154 })
155 }
156 pub fn into_owned(self) -> Mime<'static> {
157 Mime(self.0.into_owned().into(), self.1.into_owned().into())
158 }
159 pub fn major(&self) -> &str {
160 &self.0
161 }
162 pub fn minor(&self) -> &str {
163 &self.1
164 }
165}
166
167impl Display for Mime<'_> {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(f, "{}/{}", self.major(), self.minor())
170 }
171}