mime_parse_4/
constants.rs

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        // check slash, plus, and semicolon are in correct positions
81        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        // check that parsing can intern constants
100        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    // common text/ *
393    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    // common application/*
404    JSON, "json";
405    WWW_FORM_URLENCODED, "x-www-form-urlencoded";
406    MSGPACK, "msgpack";
407    OCTET_STREAM, "octet-stream";
408    PDF, "pdf";
409
410    // common font/*
411    WOFF, "woff";
412    WOFF2, "woff2";
413
414    // multipart/*
415    FORM_DATA, "form-data";
416
417    // common image/*
418    BMP, "bmp";
419    GIF, "gif";
420    JPEG, "jpeg";
421    PNG, "png";
422    SVG, "svg+xml";
423
424    // audio/*
425    BASIC, "basic";
426    MPEG, "mpeg";
427    MP4, "mp4";
428    OGG, "ogg";
429
430    // parameters
431    CHARSET, "charset";
432    BOUNDARY, "boundary";
433}
434
435mimes! {
436    //@ MediaType:
437    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    // media-ranges
471    //@ MediaRange:
472    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