1use core::ops::RangeInclusive;
2use lazy_static::lazy_static;
3
4#[derive(Clone)]
5pub struct CharFilter {
6 table: [bool; 256],
7}
8
9impl CharFilter {
10 pub fn new() -> CharFilter {
11 CharFilter {
12 table: [false; 256],
13 }
14 }
15
16 pub fn add_char(&mut self, c: u8) -> () {
17 self.table[c as usize] = true;
18 }
19
20 pub fn add_chars(&mut self, chars: RangeInclusive<u8>) -> () {
21 for c in chars {
22 self.table[c as usize] = true;
23 }
24 }
25
26 pub fn add_chars_from_slice(&mut self, chars: &[u8]) -> () {
27 for c in chars {
28 self.table[*c as usize] = true;
29 }
30 }
31
32 pub fn clone(&self) -> CharFilter {
33 CharFilter {
34 table: self.table.clone(),
35 }
36 }
37
38 pub fn invert(&mut self) -> () {
39 for i in 0..256 {
40 self.table[i] = !self.table[i];
41 }
42 }
43
44 pub fn has(&self, c: u8) -> bool {
45 unsafe { *self.table.get_unchecked(c as usize) }
46 }
47
48 pub fn iter(&self) -> impl Iterator<Item = u8> + '_ {
49 self
50 .table
51 .iter()
52 .enumerate()
53 .filter(|(_, e)| **e)
54 .map(|(c, _)| c as u8)
55 }
56}
57
58pub const ID_START_CHARSTR: &'static [u8] =
59 b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
60pub const ID_CONTINUE_CHARSTR: &'static [u8] =
61 b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
62
63lazy_static! {
64 pub static ref DIGIT: CharFilter = {
65 let mut filter = CharFilter::new();
66 filter.add_chars(b'0'..=b'9');
67 filter
68 };
69
70 pub static ref DIGIT_BIN: CharFilter = {
71 let mut filter = CharFilter::new();
72 filter.add_chars(b'0'..=b'1');
73 filter
74 };
75
76 pub static ref DIGIT_HEX: CharFilter = {
77 let mut filter = CharFilter::new();
78 filter.add_chars(b'0'..=b'9');
79 filter.add_chars(b'a'..=b'f');
80 filter.add_chars(b'A'..=b'F');
81 filter
82 };
83
84 pub static ref DIGIT_OCT: CharFilter = {
85 let mut filter = CharFilter::new();
86 filter.add_chars(b'0'..=b'8');
87 filter
88 };
89
90 pub static ref ID_START: CharFilter = {
91 let mut filter = CharFilter::new();
92 filter.add_chars_from_slice(&ID_START_CHARSTR);
93 filter
94 };
95
96 pub static ref ID_CONTINUE: CharFilter = {
97 let mut filter = ID_START.clone();
98 filter.add_chars(b'0'..=b'9');
99 filter
100 };
101
102 pub static ref WHITESPACE: CharFilter = {
103 let mut filter = CharFilter::new();
104 filter.add_char(b'\x09');
106 filter.add_char(b'\x0a');
108 filter.add_char(b'\x0b');
110 filter.add_char(b'\x0c');
112 filter.add_char(b'\x0d');
114 filter.add_char(b'\x20');
116 filter
117 };
118}