bparse/pattern/
byte.rs

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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Patterns that only match against byte slices

use crate::pattern::Prefix;
use crate::{Choice, Pattern};

/// Returns a byte pattern that will match the utf8 string slice `s` at the start of the input.
///
/// ```
/// use bparse::{Pattern, byte::utf8};
///
/// let pattern = utf8("he");
/// assert_eq!(pattern.eval(b"hello"), Some(2));
/// ```
///
/// As a convenience, the `Pattern` trait is implemented for string slices with the same effect:
///
/// ```
/// use bparse::Pattern;
///
/// assert_eq!("he".eval(b"hello"), Some(2));
/// ```
pub fn utf8(s: &str) -> Prefix<u8> {
    Prefix(s.as_bytes())
}

impl Pattern<u8> for &str {
    fn eval(&self, input: &[u8]) -> Option<usize> {
        utf8(self).eval(input)
    }
}

/// Returns a pattern that will match any byte in `bytes` at the start of the input
///
/// ```
/// use bparse::{Pattern, byte::oneof};
///
/// let pattern = oneof(b"?!.:");
/// assert_eq!(pattern.eval(b"hi"), None);
/// assert_eq!(pattern.eval(b"!!"), Some(1));
/// assert_eq!(pattern.eval(b":"), Some(1));
/// ```
pub fn oneof(bytes: &[u8]) -> ByteLookupTable {
    let mut set: [bool; 256] = [false; 256];

    let mut i = 0;
    while i < bytes.len() {
        set[bytes[i] as usize] = true;
        i += 1;
    }

    ByteLookupTable(set)
}

/// Inverse of [`oneof`].
pub fn noneof(bytes: &[u8]) -> ByteLookupTable {
    let mut set = oneof(bytes).0;
    let mut i = 0;
    while i < set.len() {
        set[i] = !set[i];
        i += 1;
    }

    ByteLookupTable(set)
}

/// See [`oneof`]
#[derive(Debug, Clone, Copy)]
pub struct ByteLookupTable([bool; 256]);

impl Pattern<u8> for ByteLookupTable {
    fn eval<'i>(&self, input: &[u8]) -> Option<usize> {
        let first = *input.first()?;

        if self.0[first as usize] {
            return Some(1);
        }
        None
    }
}

/// Returns a pattern that will match any ascii digit at the start of the input
///
/// ```
/// use bparse::{Pattern, byte::digit};
///
/// assert_eq!(digit().eval(b"a"), None);
/// assert_eq!(digit().eval(b"8"), Some(1));
/// ```
pub fn digit() -> ByteLookupTable {
    oneof(b"0123456789")
}

/// Returns a pattern that will match any ascii letter at the start of the input
///
/// ```
/// use bparse::{Pattern, byte::alpha};
///
/// assert_eq!(alpha().eval(b"1"), None);
/// assert_eq!(alpha().eval(b"a"), Some(1));
/// ```
pub fn alpha() -> ByteLookupTable {
    oneof(b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
}

/// Returns a pattern that will match any hexadecimal character at the start of the input
///
/// ```
/// use bparse::{Pattern, byte::hex};
///
/// assert_eq!(hex().eval(b"z"), None);
/// assert_eq!(hex().eval(b"f"), Some(1));
/// ```
pub fn hex() -> Choice<ByteLookupTable, ByteLookupTable> {
    oneof(b"abcdefABCDEF").or(digit())
}