1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
use std::borrow::ToOwned;
use std::fmt;

use regex;

#[derive(Clone, PartialEq, Eq, Debug)]
pub enum MimeType {
    Text,
    Html,
    Xhtml,
    Other(String),
}

fn mimetype_pattern() -> regex::Regex {
    regex::Regex::new(concat!(
        r#"^"#,
        r#"(?P<type>[A-Za-z0-9!#$&.+^_-]{1,127})"#,
        r#"/"#,
        r#"(?P<subtype>[A-Za-z0-9!#$&.+^_-]{1,127})"#,
        r#"$"#
    )).unwrap()
}

impl MimeType {
    pub fn from_str(mimetype: &str) -> Option<MimeType> {
        let captures = mimetype_pattern().captures(mimetype);
        if let Some(captures) = captures {
            Some(match (captures.name("type"), captures.name("subtype")) {
                (Some("text"), Some("plain")) => MimeType::Text,
                (Some("text"), Some("html")) => MimeType::Html,
                (Some("application"), Some("xhtml+xml")) => MimeType::Xhtml,
                _ => MimeType::Other(mimetype.to_owned()),
            })
        } else {
            None
        }
    }

    pub fn mimetype(&self) -> &str {
        match *self {
            MimeType::Text => "text/plain",
            MimeType::Html => "text/html",
            MimeType::Xhtml => "application/xhtml+xml",
            MimeType::Other(ref mimetype) => &mimetype,
        }
    }

    pub fn is_text(&self) -> bool {
        match *self {
            MimeType::Other(ref _mimetype) => false,
            _ => true
        }
    }
}

impl fmt::Display for MimeType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.mimetype())
    }
}