parser_helper/
lib.rs

1use std::fmt::Debug;
2
3/// A trait that is implemented for everything that can be a sequence of bytes
4pub trait ParseHelper: AsRef<[u8]> {
5    /// Skips prefix of slice until sequence is found
6    fn take_until(&self, pattern: &[u8]) -> Result<(&[u8], &[u8]), ()> {
7        let source = self.as_ref();
8        if source.len() < pattern.len() {
9            return Err(());
10        }
11        for i in 0..=source.len() - pattern.len() {
12            if source[i..].starts_with(pattern) {
13                return Ok((&source[..i], &source[i..]));
14            }
15        }
16        Err(())
17    }
18
19    /// Skips prefix of slice until sequence is found and returns provided error if not
20    fn take_until_err<E: Debug>(&self, pattern: &[u8], err: E) -> Result<(&[u8], &[u8]), E> {
21        self.take_until(pattern).map_err(|_| err)
22    }
23
24    /// Returns a slice of exact length
25    fn take_exact(&self, count: usize) -> Result<(&[u8], &[u8]), ()> {
26        let source = self.as_ref();
27        if source.len() < count {
28            return Err(());
29        }
30        Ok((&source[..count], &source[count..]))
31    }
32
33    /// Returns a slice of exact length and returns provided error if not
34    fn take_exact_err<E: Debug>(&self, count: usize, err: E) -> Result<(&[u8], &[u8]), E> {
35        self.take_exact(count).map_err(|_| err)
36    }
37
38    /// Returns a slice of the provided pattern and the rest of the slice
39    fn take_expect(&self, pattern: &[u8]) -> Result<(&[u8], &[u8]), &[u8]> {
40        let source = self.as_ref();
41        if source.len() < pattern.len() {
42            return Err(source);
43        }
44        for i in 0..pattern.len() {
45            if source[i] != pattern[i] {
46                return Err(source);
47            }
48        }
49        Ok((&source[..pattern.len()], &source[pattern.len()..]))
50    }
51
52    /// Returns a slice of the provided pattern and the rest of the slice and returns provided error if not
53    fn take_expect_err<E: Debug>(&self, pattern: &[u8], err: E) -> Result<(&[u8], &[u8]), E> {
54        self.take_expect(pattern).map_err(|_| err)
55    }
56
57    /// If the next pattern is optional, it may return it, otherwise it returns the original slice
58    fn maybe_expect(&self, pattern: &[u8]) -> (Option<&[u8]>, &[u8]) {
59        match self.take_expect(pattern) {
60            Ok((first, second)) => (Some(first), second),
61            Err(_) => (None, self.as_ref())
62        }
63    }
64
65    /// Returns the smallest first slice found from the start that matches the condition
66    /// i.e. it runs the function until the first time it is true
67    fn take_smallest_err<E: Debug, F: Fn(&[u8]) -> bool>(&self, f: F, min_size: usize, err: E) -> Result<(&[u8], &[u8]), E> {
68        for i in min_size..self.as_ref().len() {
69            if f(&self.as_ref()[..i]) {
70                return Ok((&self.as_ref()[..i], &self.as_ref()[i..]))
71            }
72        }
73        Err(err)
74    }
75
76    /// Returns the largest slice found from the start that matches the condition.
77    /// i.e. it runs the function until the last time it is true
78    fn take_largest_err<E: Debug, F: Fn(&[u8]) -> bool>(&self, f: F, min_size:usize, err: E) -> Result<(&[u8], &[u8]), E> {
79        let mut largest = None;
80        for i in min_size..self.as_ref().len() {
81            if f(&self.as_ref()[..i]) {
82                largest = Some(i);
83            }
84        };
85        largest.map(|i| (&self.as_ref()[..i], &self.as_ref()[i..])).ok_or(err)
86    }
87}
88
89impl ParseHelper for &[u8] {}
90impl ParseHelper for [u8] {}
91impl ParseHelper for Vec<u8> {}
92impl ParseHelper for &str {}
93
94#[cfg(test)]
95mod test {
96    use crate::ParseHelper;
97
98    #[test]
99    fn test_take_until() {
100        let source = b"hello world";
101        let pattern = b" ";
102        let (before, after) = source.take_until(pattern).unwrap();
103        assert_eq!(before, b"hello");
104        assert_eq!(after, b" world");
105
106        let (before,after) = "GET / HTTP/1.1\r\n\r\n".take_until(b"\r\n\r\n").unwrap();
107        assert_eq!(before, b"GET / HTTP/1.1");
108        assert_eq!(after, b"\r\n\r\n");
109    }
110
111    #[test]
112    fn take_exact() {
113        let source = b"hello world";
114        let (exact, after) = source.take_exact(5).unwrap();
115        assert_eq!(exact, b"hello");
116        assert_eq!(after, b" world");
117    }
118
119    #[test]
120    fn take_expect() {
121        let source = b"hello world";
122        let (matching, remained) = source.take_expect(b"hello ").unwrap();
123        assert_eq!(matching, b"hello ");
124        assert_eq!(remained, b"world");
125    }
126
127    #[test]
128    fn take_smallest() {
129        let source = b"aaaabbbbcccc";
130        assert!(source.take_smallest_err(|s| s.starts_with(b"bbbb"), 0, ()).is_err());
131
132        let (first ,second) = source.take_smallest_err(|s| !s.contains(&b"b"[0]), 0, ()).unwrap();
133        assert_eq!(first, b"a");
134        assert_eq!(second, b"aaabbbbcccc");
135    }
136
137    #[test]
138    fn take_largest() {
139        let source = b"aaaabbbbcccc";
140
141        let func = |s: &[u8]| s.starts_with(b"b");
142        assert!(source.take_largest_err(func, 0, ()).is_err());
143
144        let func = |s: &[u8]| !s.contains(&b"b"[0]);
145        let (first, second) = source.take_largest_err(func, 0, ()).unwrap();
146        assert_eq!(first, b"aaaa");
147        assert_eq!(second, b"bbbbcccc");
148    }
149}