1use super::{InternParams, Mime, ParamSource, Source};
2
3macro_rules! mimes {
4 ($($id:ident, $($piece:expr),+;)+) => (
5 #[allow(non_camel_case_types)]
6 enum __Atoms {
7 __Dynamic,
8 $(
9 $id,
10 )+
11 }
12
13 $(
14 mime_constant! {
15 $id, $($piece),+
16 }
17 )+
18
19 #[test]
20 fn test_mimes_macro_consts() {
21 $(
22 mime_constant_test! {
23 $id, $($piece),*
24 }
25 )+
26 }
27 )
28}
29
30pub(super) enum Atoms {}
31
32macro_rules! mime_constant {
33 ($id:ident, $src:expr, $slash:expr) => (
34 mime_constant!($id, $src, $slash, None);
35 );
36 ($id:ident, $src:expr, $slash:expr, $plus:expr) => (
37 mime_constant!(FULL $id, $src, $slash, $plus, ParamSource::None);
38 );
39
40 ($id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => (
41 mime_constant!(FULL $id, $src, $slash, $plus, ParamSource::Utf8($params));
42 );
43
44
45 (FULL $id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => (
46
47 impl Atoms {
48 const $id: Source = Source::Atom(__Atoms::$id as u8, $src);
49 }
50
51 #[doc = "`"]
52 #[doc = $src]
53 #[doc = "`"]
54 pub const $id: Mime = Mime {
55 source: Atoms::$id,
56 slash: $slash,
57 plus: $plus,
58 params: $params,
59 };
60 )
61}
62
63
64#[cfg(test)]
65macro_rules! mime_constant_test {
66 ($id:ident, $src:expr, $slash:expr) => (
67 mime_constant_test!($id, $src, $slash, None);
68 );
69 ($id:ident, $src:expr, $slash:expr, $plus:expr) => (
70 mime_constant_test!(FULL $id, $src, $slash, $plus, ParamSource::None);
71 );
72
73 ($id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => (
74 mime_constant_test!(FULL $id, $src, $slash, $plus, ParamSource::Utf8($params));
75 );
76
77 (FULL $id:ident, $src:expr, $slash:expr, $plus:expr, $params:expr) => ({
78 let mime = $id;
79
80 let slash = mime.as_ref().as_bytes()[$slash];
82 assert_eq!(slash, b'/', "{:?} has {:?} at slash position {:?}", mime, slash as char, $slash);
83 if let Some(plus) = mime.plus {
84 let c_plus = mime.as_ref().as_bytes()[plus as usize];
85 assert_eq!(c_plus, b'+', "{:?} has {:?} at plus position {:?}", mime, c_plus as char, plus);
86 } else {
87 assert!(!mime.as_ref().as_bytes().contains(&b'+'), "{:?} forgot plus", mime);
88 }
89 if let ParamSource::Utf8(semicolon) = mime.params {
90 assert_eq!(mime.as_ref().as_bytes()[semicolon as usize], b';');
91 assert_eq!(&mime.as_ref()[semicolon as usize ..], "; charset=utf-8");
92 } else if let ParamSource::None = mime.params {
93 assert!(!mime.as_ref().as_bytes().contains(&b';'));
94 } else {
95 unreachable!("consts wont have ParamSource::Custom");
96 }
97
98
99 match mime.params {
101 ParamSource::None | ParamSource::Utf8(_) => {
102 let parsed = crate::Parser::can_range().parse($src).expect("parse const");
103 match parsed.source {
104 Source::Atom(_, $src) => (),
105 Source::Atom(_, src) => {
106 panic!(
107 "did not intern {:?} correctly: {:?}",
108 $src,
109 src,
110 );
111 },
112 _ => {
113 panic!(
114 "did not intern an Atom {:?}: slash={}, sub={}",
115 $src,
116 $slash,
117 $src.len() - $slash - 1,
118 );
119 }
120 }
121 },
122 _ => (),
123 }
124 })
125}
126
127impl Atoms {
128 pub(super) fn intern(s: &str, slash: u16, params: InternParams) -> Source {
129 let slash = slash as usize;
130 debug_assert!(
131 s.len() > slash,
132 "intern called with illegal slash position: {:?}[{:?}]",
133 s,
134 slash,
135 );
136
137 match params {
138 InternParams::Utf8(semicolon) => {
139 Atoms::intern_charset_utf8(s, slash, semicolon)
140 },
141 InternParams::None => {
142 Atoms::intern_no_params(s, slash)
143 },
144 }
145 }
146
147 fn intern_charset_utf8(s: &str, slash: usize, semicolon: usize) -> Source {
148 use self::names::*;
149 let top = &s[..slash];
150 let sub = &s[slash + 1..semicolon];
151
152 if top == TEXT {
153 if sub == PLAIN {
154 return Atoms::TEXT_PLAIN_UTF_8;
155 }
156 if sub == HTML {
157 return Atoms::TEXT_HTML_UTF_8;
158 }
159 if sub == CSS {
160 return Atoms::TEXT_CSS_UTF_8;
161 }
162 if sub == CSV {
163 return Atoms::TEXT_CSV_UTF_8;
164 }
165 if sub == TAB_SEPARATED_VALUES {
166 return Atoms::TEXT_TAB_SEPARATED_VALUES_UTF_8;
167 }
168 }
169 if top == APPLICATION {
170 if sub == JAVASCRIPT {
171 return Atoms::APPLICATION_JAVASCRIPT_UTF_8;
172 }
173 }
174
175 Atoms::dynamic(s)
176 }
177
178 fn intern_no_params(s: &str, slash: usize) -> Source {
179 use self::names::*;
180 let top = &s[..slash];
181 let sub = &s[slash + 1..];
182
183 match slash {
184 4 => {
185 if top == TEXT {
186 match sub.len() {
187 1 => {
188 if sub.as_bytes()[0] == b'*' {
189 return Atoms::TEXT_STAR;
190 }
191 }
192 3 => {
193 if sub == CSS {
194 return Atoms::TEXT_CSS;
195 }
196 if sub == XML {
197 return Atoms::TEXT_XML;
198 }
199 if sub == CSV {
200 return Atoms::TEXT_CSV;
201 }
202 },
203 4 => {
204 if sub == HTML {
205 return Atoms::TEXT_HTML;
206 }
207 }
208 5 => {
209 if sub == PLAIN {
210 return Atoms::TEXT_PLAIN;
211 }
212 if sub == VCARD {
213 return Atoms::TEXT_VCARD;
214 }
215 }
216 10 => {
217 if sub == JAVASCRIPT {
218 return Atoms::TEXT_JAVASCRIPT;
219 }
220 }
221 12 => {
222 if sub == EVENT_STREAM {
223 return Atoms::TEXT_EVENT_STREAM;
224 }
225 },
226 20 => {
227 if sub == TAB_SEPARATED_VALUES {
228 return Atoms::TEXT_TAB_SEPARATED_VALUES;
229 }
230 }
231 _ => (),
232 }
233 } else if top == FONT {
234 match sub.len() {
235 4 => {
236 if sub == WOFF {
237 return Atoms::FONT_WOFF;
238 }
239 },
240 5 => {
241 if sub == WOFF2 {
242 return Atoms::FONT_WOFF2;
243 }
244 },
245 _ => (),
246 }
247 }
248 },
249 5 => {
250 if top == IMAGE {
251 match sub.len() {
252 1 => {
253 if sub.as_bytes()[0] == b'*' {
254 return Atoms::IMAGE_STAR;
255 }
256 }
257 3 => {
258 if sub == PNG {
259 return Atoms::IMAGE_PNG;
260 }
261 if sub == GIF {
262 return Atoms::IMAGE_GIF;
263 }
264 if sub == BMP {
265 return Atoms::IMAGE_BMP;
266 }
267 }
268 4 => {
269 if sub == JPEG {
270 return Atoms::IMAGE_JPEG;
271 }
272 },
273 7 => {
274 if sub == SVG {
275 return Atoms::IMAGE_SVG;
276 }
277 },
278 _ => (),
279
280 }
281 } else if top == VIDEO {
282 match sub.len() {
283 1 => {
284 if sub.as_bytes()[0] == b'*' {
285 return Atoms::VIDEO_STAR;
286 }
287 },
288 _ => (),
289 }
290 } else if top == AUDIO {
291 match sub.len() {
292 1 => {
293 if sub.as_bytes()[0] == b'*' {
294 return Atoms::AUDIO_STAR;
295 }
296 },
297 _ => (),
298 }
299 }
300 },
301 11 => {
302 if top == APPLICATION {
303 match sub.len() {
304 3 => {
305 if sub == PDF {
306 return Atoms::APPLICATION_PDF;
307 }
308 }
309 4 => {
310 if sub == JSON {
311 return Atoms::APPLICATION_JSON;
312 }
313 },
314 7 => {
315 if sub == MSGPACK {
316 return Atoms::APPLICATION_MSGPACK;
317 }
318 },
319 10 => {
320 if sub == JAVASCRIPT {
321 return Atoms::APPLICATION_JAVASCRIPT;
322 }
323 },
324 11 => {
325 if sub == "dns-message" {
326 return Atoms::APPLICATION_DNS;
327 }
328 },
329 12 => {
330 if sub == OCTET_STREAM {
331 return Atoms::APPLICATION_OCTET_STREAM;
332 }
333 }
334 21 => {
335 if sub == WWW_FORM_URLENCODED {
336 return Atoms::APPLICATION_WWW_FORM_URLENCODED;
337 }
338 }
339 _ => (),
340 }
341 }
342 }
343 _ => (),
344 }
345
346 Atoms::dynamic(s)
347 }
348
349 fn dynamic(s: &str) -> Source {
350 Source::Dynamic(s.to_ascii_lowercase())
351 }
352}
353
354macro_rules! names {
355 ($($id:ident, $e:expr;)*) => (
356 pub mod names {
357 $(
358 names! {
359 @DOC concat!("The string literal `\"", $e, "\"`."),
360 $id,
361 $e
362 }
363 )*
364
365 #[test]
366 fn test_names_macro_consts() {
367 $(
368 assert_eq!($id.to_ascii_lowercase(), $id);
369 )*
370 }
371 }
372 );
373 (@DOC $doc:expr, $id:ident, $e:expr) => (
374 #[doc = $doc]
375 pub const $id: &'static str = $e;
376 )
377}
378
379names! {
380 STAR, "*";
381
382 TEXT, "text";
383 IMAGE, "image";
384 AUDIO, "audio";
385 VIDEO, "video";
386 APPLICATION, "application";
387 MULTIPART, "multipart";
388 MESSAGE, "message";
389 MODEL, "model";
390 FONT, "font";
391
392 PLAIN, "plain";
394 HTML, "html";
395 XML, "xml";
396 JAVASCRIPT, "javascript";
397 CSS, "css";
398 CSV, "csv";
399 EVENT_STREAM, "event-stream";
400 VCARD, "vcard";
401 TAB_SEPARATED_VALUES, "tab-separated-values";
402
403 JSON, "json";
405 WWW_FORM_URLENCODED, "x-www-form-urlencoded";
406 MSGPACK, "msgpack";
407 OCTET_STREAM, "octet-stream";
408 PDF, "pdf";
409
410 WOFF, "woff";
412 WOFF2, "woff2";
413
414 FORM_DATA, "form-data";
416
417 BMP, "bmp";
419 GIF, "gif";
420 JPEG, "jpeg";
421 PNG, "png";
422 SVG, "svg+xml";
423
424 BASIC, "basic";
426 MPEG, "mpeg";
427 MP4, "mp4";
428 OGG, "ogg";
429
430 CHARSET, "charset";
432 BOUNDARY, "boundary";
433}
434
435mimes! {
436 TEXT_PLAIN, "text/plain", 4;
438 TEXT_PLAIN_UTF_8, "text/plain; charset=utf-8", 4, None, 10;
439 TEXT_HTML, "text/html", 4;
440 TEXT_HTML_UTF_8, "text/html; charset=utf-8", 4, None, 9;
441 TEXT_CSS, "text/css", 4;
442 TEXT_CSS_UTF_8, "text/css; charset=utf-8", 4, None, 8;
443 TEXT_JAVASCRIPT, "text/javascript", 4;
444 TEXT_XML, "text/xml", 4;
445 TEXT_EVENT_STREAM, "text/event-stream", 4;
446 TEXT_CSV, "text/csv", 4;
447 TEXT_CSV_UTF_8, "text/csv; charset=utf-8", 4, None, 8;
448 TEXT_TAB_SEPARATED_VALUES, "text/tab-separated-values", 4;
449 TEXT_TAB_SEPARATED_VALUES_UTF_8, "text/tab-separated-values; charset=utf-8", 4, None, 25;
450 TEXT_VCARD, "text/vcard", 4;
451
452 IMAGE_JPEG, "image/jpeg", 5;
453 IMAGE_GIF, "image/gif", 5;
454 IMAGE_PNG, "image/png", 5;
455 IMAGE_BMP, "image/bmp", 5;
456 IMAGE_SVG, "image/svg+xml", 5, Some(9);
457
458 FONT_WOFF, "font/woff", 4;
459 FONT_WOFF2, "font/woff2", 4;
460
461 APPLICATION_JSON, "application/json", 11;
462 APPLICATION_JAVASCRIPT, "application/javascript", 11;
463 APPLICATION_JAVASCRIPT_UTF_8, "application/javascript; charset=utf-8", 11, None, 22;
464 APPLICATION_WWW_FORM_URLENCODED, "application/x-www-form-urlencoded", 11;
465 APPLICATION_OCTET_STREAM, "application/octet-stream", 11;
466 APPLICATION_MSGPACK, "application/msgpack", 11;
467 APPLICATION_PDF, "application/pdf", 11;
468 APPLICATION_DNS, "application/dns-message", 11;
469
470 STAR_STAR, "*/*", 1;
473 TEXT_STAR, "text/*", 4;
474 IMAGE_STAR, "image/*", 5;
475 VIDEO_STAR, "video/*", 5;
476 AUDIO_STAR, "audio/*", 5;
477}
478