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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
use super::*;

#[derive(Debug, Display, From)]
pub enum Error {
    Regex(fancy_regex::Error),
}

#[derive(Debug)]
pub struct Matcher {
    regex: fancy_regex::Regex,
    device_replacement: Option<String>,
    brand_replacement: Option<String>,
    model_replacement: Option<String>,
}

impl SubParser for Matcher {
    type Item = Device;

    fn try_parse(&self, text: &str) -> Option<Self::Item> {
        if let Ok(Some(captures)) = self.regex.captures(text) {
            let family: String =
                if let Some(device_replacement) = &self.device_replacement {
                    replace(&device_replacement, &captures)
                } else {
                    captures
                        .get(1)
                        .map(|x| x.as_str())
                        .and_then(none_if_empty)
                        .map(ToString::to_string)?
                };

            let brand: Option<String> =
                if let Some(brand_replacement) = &self.brand_replacement {
                    none_if_empty(replace(&brand_replacement, &captures))
                } else {
                    None
                };

            let model: Option<String> =
                if let Some(model_replacement) = &self.model_replacement {
                    none_if_empty(replace(&model_replacement, &captures))
                } else {
                    captures
                        .get(1)
                        .map(|x| x.as_str())
                        .and_then(none_if_empty)
                        .map(ToString::to_string)
                };

            Some(Device {
                family,
                brand,
                model,
            })
        } else {
            None
        }
    }
}

impl Matcher {
    pub fn try_from(entry: DeviceParserEntry) -> Result<Matcher, Error> {
        let regex_with_flags =
            if !entry.regex_flag.as_ref().map_or(true, String::is_empty) {
                format!("(?{}){}", entry.regex_flag.unwrap_or_default(), entry.regex)
            } else {
                entry.regex.to_owned()
            };
        let regex = fancy_regex::RegexBuilder::new(&regex_with_flags)
            .delegate_size_limit(20 * (1 << 20))
            .build();

        Ok(Matcher {
            regex: regex?,
            device_replacement: entry.device_replacement,
            brand_replacement: entry.brand_replacement,
            model_replacement: entry.model_replacement,
        })
    }
}