| 
1 | 1 | use anyhow::{anyhow, Error};  | 
2 |  | -use regex::Regex;  | 
3 | 2 | 
 
  | 
4 | 3 | pub struct KeyFinder {  | 
5 |  | -    keys: Option<(usize, usize, Vec<bool>)>,  | 
6 |  | -    sep: Regex,  | 
 | 4 | +    keys: Option<(Vec<usize>, usize)>,  | 
7 | 5 | }  | 
8 | 6 | 
 
  | 
9 | 7 | impl KeyFinder {  | 
10 |  | -    pub fn new(keys: Option<Vec<usize>>, sep: Regex) -> Result<Self, Error> {  | 
 | 8 | +    pub fn new(keys: Option<Vec<usize>>) -> Self {  | 
11 | 9 |         let keys = keys.map(|mut keys| {  | 
12 | 10 |             keys.sort();  | 
13 | 11 | 
 
  | 
14 | 12 |             let last = *keys.last().unwrap();  | 
15 |  | -            (  | 
16 |  | -                keys.len(),  | 
17 |  | -                last,  | 
18 |  | -                (0..=last)  | 
19 |  | -                    .map(|i| keys.contains(&(i + 1)))  | 
20 |  | -                    .collect::<Vec<_>>(),  | 
21 |  | -            )  | 
 | 13 | +            let keep = (0..=last)  | 
 | 14 | +                .map(|i| keys.contains(&(i + 1)))  | 
 | 15 | +                .collect::<Vec<_>>();  | 
 | 16 | + | 
 | 17 | +            let mut offsets = Vec::new();  | 
 | 18 | +            let mut last = usize::MAX;  | 
 | 19 | +            for (idx, &k) in keep.iter().enumerate() {  | 
 | 20 | +                if k {  | 
 | 21 | +                    offsets.push(idx.wrapping_sub(last).wrapping_sub(1));  | 
 | 22 | +                    last = idx;  | 
 | 23 | +                }  | 
 | 24 | +            }  | 
 | 25 | +            (offsets, last)  | 
22 | 26 |         });  | 
23 |  | -        Ok(KeyFinder { keys, sep })  | 
 | 27 | +        KeyFinder { keys }  | 
24 | 28 |     }  | 
25 | 29 | 
 
  | 
26 | 30 |     pub fn key<'a>(&self, record: &'a str, s: &'a mut String) -> Result<&'a str, Error> {  | 
27 |  | -        let (num, last, keep) = match &self.keys {  | 
 | 31 | +        let (keep, last) = match &self.keys {  | 
28 | 32 |             None => return Ok(record),  | 
29 |  | -            Some((num, _, _)) if *num == 0 => return Ok(record),  | 
30 |  | -            Some((num, last, keep)) => (num, last, keep),  | 
 | 33 | +            Some(keep) if keep.0.len() == 0 => return Ok(record),  | 
 | 34 | +            Some(keep) => keep,  | 
31 | 35 |         };  | 
32 | 36 | 
 
  | 
33 |  | -        let mut fields = keep  | 
34 |  | -            .iter()  | 
35 |  | -            .zip(self.sep.splitn(record, last + 2))  | 
36 |  | -            .filter_map(|(keep, field)| if *keep { Some(field) } else { None });  | 
37 |  | - | 
38 |  | -        if *num == 1 {  | 
39 |  | -            return match fields.next() {  | 
40 |  | -                Some(f) => Ok(f),  | 
41 |  | -                None => Err(anyhow!("not enough fields to make key")),  | 
42 |  | -            };  | 
 | 37 | +        let mut current = 0;  | 
 | 38 | +        let mut iter = record.splitn(last + 2, |c| (c == ' ' || c == '\t'));  | 
 | 39 | +        for &offset in keep {  | 
 | 40 | +            match iter.nth(offset) {  | 
 | 41 | +                None => break,  | 
 | 42 | +                Some(field) => {  | 
 | 43 | +                    if current > 0 {  | 
 | 44 | +                        s.push(' ');  | 
 | 45 | +                    }  | 
 | 46 | +                    s.push_str(field);  | 
 | 47 | +                    current += 1;  | 
 | 48 | +                }  | 
 | 49 | +            }  | 
43 | 50 |         }  | 
44 | 51 | 
 
  | 
45 |  | -        let mut found = 0;  | 
46 |  | -        for f in fields {  | 
47 |  | -            s.push(' ');  | 
48 |  | -            s.push_str(f);  | 
49 |  | -            found += 1;  | 
50 |  | -        }  | 
51 |  | - | 
52 |  | -        if found == *num {  | 
 | 52 | +        if current >= keep.len() {  | 
53 | 53 |             Ok(s)  | 
54 | 54 |         } else {  | 
55 | 55 |             Err(anyhow!("not enough fields to make key"))  | 
56 | 56 |         }  | 
57 | 57 |     }  | 
58 | 58 | }  | 
 | 59 | + | 
 | 60 | +#[cfg(test)]  | 
 | 61 | +mod tests {  | 
 | 62 | +    use super::*;  | 
 | 63 | + | 
 | 64 | +    #[test]  | 
 | 65 | +    fn key() {  | 
 | 66 | +        let kf = KeyFinder::new(Some(vec![1]));  | 
 | 67 | +        let mut s = String::new();  | 
 | 68 | +        assert_eq!(kf.key(TEST, &mut s).unwrap(), "92.109.155.34");  | 
 | 69 | + | 
 | 70 | +        s.clear();  | 
 | 71 | +        let kf = KeyFinder::new(Some(vec![7]));  | 
 | 72 | +        assert_eq!(kf.key(TEST, &mut s).unwrap(), "/");  | 
 | 73 | +    }  | 
 | 74 | + | 
 | 75 | +    const TEST: &str = "92.109.155.34 - - [09/Aug/2018:11:53:26 +0200] \"GET / HTTP/2.0\" 200 3219 \"https://www.facebook.com/\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36\"";  | 
 | 76 | +}  | 
0 commit comments