1use core::ops::RangeInclusive;
2use once_cell::sync::Lazy;
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 { table: self.table }
34 }
35
36 pub fn invert(&mut self) {
37 for i in 0..256 {
38 self.table[i] = !self.table[i];
39 }
40 }
41
42 pub fn has(&self, c: u8) -> bool {
43 unsafe { *self.table.get_unchecked(c as usize) }
44 }
45
46 pub fn iter(&self) -> impl Iterator<Item = u8> + '_ {
47 self
48 .table
49 .iter()
50 .enumerate()
51 .filter(|(_, e)| **e)
52 .map(|(c, _)| c as u8)
53 }
54}
55
56pub const ID_START_CHARSTR: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
58pub const ID_CONTINUE_CHARSTR: &[u8] =
59 b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
60
61pub static DIGIT: Lazy<CharFilter> = Lazy::new(|| {
62 let mut filter = CharFilter::new();
63 filter.add_chars(b'0'..=b'9');
64 filter
65});
66
67pub static DIGIT_BIN: Lazy<CharFilter> = Lazy::new(|| {
68 let mut filter = CharFilter::new();
69 filter.add_chars(b'0'..=b'1');
70 filter
71});
72
73pub static DIGIT_HEX: Lazy<CharFilter> = Lazy::new(|| {
74 let mut filter = CharFilter::new();
75 filter.add_chars(b'0'..=b'9');
76 filter.add_chars(b'a'..=b'f');
77 filter.add_chars(b'A'..=b'F');
78 filter
79});
80
81pub static DIGIT_OCT: Lazy<CharFilter> = Lazy::new(|| {
82 let mut filter = CharFilter::new();
83 filter.add_chars(b'0'..=b'8');
84 filter
85});
86
87pub static ID_START: Lazy<CharFilter> = Lazy::new(|| {
88 let mut filter = CharFilter::new();
89 filter.add_chars_from_slice(ID_START_CHARSTR);
90 filter
91});
92
93pub static ID_CONTINUE: Lazy<CharFilter> = Lazy::new(|| {
94 let mut filter = ID_START.clone();
95 filter.add_chars(b'0'..=b'9');
97 filter
98});
99
100pub static ID_CONTINUE_JSX: Lazy<CharFilter> = Lazy::new(|| {
101 let mut filter = ID_CONTINUE.clone();
102 filter.add_char(b'-');
103 filter
104});
105
106pub static ID_CONTINUE_OR_PARENTHESIS_CLOSE_OR_BRACKET_CLOSE: Lazy<CharFilter> = Lazy::new(|| {
107 let mut filter = ID_CONTINUE.clone();
108 filter.add_char(b')');
109 filter.add_char(b']');
110 filter
111});
112
113pub static WHITESPACE: Lazy<CharFilter> = Lazy::new(|| {
114 let mut filter = CharFilter::new();
115 filter.add_char(b'\x09');
118 filter.add_char(b'\x0a');
120 filter.add_char(b'\x0b');
122 filter.add_char(b'\x0c');
124 filter.add_char(b'\x0d');
126 filter.add_char(b'\x20');
128 filter
129});