noa_parser/bytes/
matchers.rs

1/// Attempt to match a single character against a byte slice.
2///
3/// # Arguments
4///
5/// * `pattern` - The character to match against.
6/// * `data` - The byte slice to match against.
7///
8/// # Returns
9///
10/// A tuple containing a boolean indicating whether the match succeeded and
11/// the number of bytes consumed if the match succeeded.
12pub fn match_char(pattern: char, data: &[u8]) -> (bool, usize) {
13    (pattern as u8 == data[0], 1)
14}
15
16/// Attempt to match a byte slice against a byte slice.
17///
18/// # Arguments
19///
20/// * `pattern` - The byte slice to match against.
21/// * `data` - The byte slice to match against.
22///
23/// # Returns
24///
25/// A tuple containing a boolean indicating whether the match succeeded and
26/// the number of bytes consumed if the match succeeded.
27pub fn match_pattern(pattern: &[u8], data: &[u8]) -> (bool, usize) {
28    if pattern.is_empty() {
29        return (false, 0);
30    }
31
32    if pattern.len() > data.len() {
33        return (false, 0);
34    }
35
36    if pattern.eq_ignore_ascii_case(&data[..pattern.len()]) {
37        return (true, pattern.len());
38    }
39
40    (false, 0)
41}
42
43/// Attempt to match a number against a byte slice.
44///
45/// # Arguments
46///
47/// * `data` - The byte slice to match against.
48///
49/// # Returns
50///
51/// A tuple containing a boolean indicating whether the match succeeded and
52/// the number of bytes consumed if the match succeeded.
53pub fn match_number(data: &[u8]) -> (bool, usize) {
54    if data.is_empty() {
55        return (false, 0);
56    }
57
58    let mut pos = 0;
59    let mut found = false;
60
61    loop {
62        if pos == data.len() {
63            break;
64        }
65        if data[pos].is_ascii_digit() {
66            pos += 1;
67            found = true;
68            continue;
69        }
70        break;
71    }
72
73    (found, pos)
74}
75
76/// Attempt to match a string against a byte slice.
77/// Stop matching when a punctuation character is encountered.
78///  * U+0021 ..= U+002F ! " # $ % & ' ( ) * + , - . /, or
79///  * U+003A ..= U+0040 : ; < = > ? @, or
80///  * U+005B ..= U+0060 [ \ ] ^ _ `, or
81///  * U+007B ..= U+007E { | } ~
82///
83/// # Arguments
84///
85/// * `data` - The byte slice to match against.
86///
87/// # Returns
88///
89/// A tuple containing a boolean indicating whether the match succeeded and
90/// the number of bytes consumed if the match succeeded.
91pub fn match_string(data: &[u8]) -> (bool, usize) {
92    if data.is_empty() {
93        return (false, 0);
94    }
95
96    let mut pos = 0;
97    let mut found = false;
98
99    loop {
100        if pos == data.len() {
101            break;
102        }
103        if !data[pos].is_ascii_punctuation() {
104            pos += 1;
105            found = true;
106            continue;
107        }
108        break;
109    }
110
111    (found, pos)
112}
113
114#[cfg(test)]
115mod tests {
116    use crate::bytes::matchers::{match_char, match_number, match_pattern, match_string};
117
118    #[test]
119    fn test_match_char() {
120        let (result, consumed) = match_char('a', b"abc");
121        assert!(result);
122        assert_eq!(consumed, 1);
123
124        let (result, consumed) = match_char('b', b"abc");
125        assert!(!result);
126        assert_eq!(consumed, 1);
127    }
128
129    #[test]
130    fn test_match_pattern() {
131        let (result, consumed) = match_pattern(b"abc", b"abcdef");
132        assert!(result);
133        assert_eq!(consumed, 3);
134
135        let (result, consumed) = match_pattern(b"abc", b"bbcdefg");
136        assert!(!result);
137        assert_eq!(consumed, 0);
138    }
139
140    #[test]
141    fn test_match_number() {
142        let (result, consumed) = match_number(b"123abc");
143        assert!(result);
144        assert_eq!(consumed, 3);
145
146        let (result, consumed) = match_number(b"abc123");
147        assert!(!result);
148        assert_eq!(consumed, 0);
149    }
150
151    #[test]
152    fn test_match_string() {
153        let (result, consumed) = match_string(b"abc123(");
154        assert!(result);
155        assert_eq!(consumed, 6);
156    }
157}