json_threat_protection/read/
utils.rs

1pub const IS_HEX: [bool; 256] = {
2    let mut is_hex = [false; 256];
3    is_hex[b'0' as usize] = true;
4    is_hex[b'1' as usize] = true;
5    is_hex[b'2' as usize] = true;
6    is_hex[b'3' as usize] = true;
7    is_hex[b'4' as usize] = true;
8    is_hex[b'5' as usize] = true;
9    is_hex[b'6' as usize] = true;
10    is_hex[b'7' as usize] = true;
11    is_hex[b'8' as usize] = true;
12    is_hex[b'9' as usize] = true;
13    is_hex[b'a' as usize] = true;
14    is_hex[b'b' as usize] = true;
15    is_hex[b'c' as usize] = true;
16    is_hex[b'd' as usize] = true;
17    is_hex[b'e' as usize] = true;
18    is_hex[b'f' as usize] = true;
19    is_hex[b'A' as usize] = true;
20    is_hex[b'B' as usize] = true;
21    is_hex[b'C' as usize] = true;
22    is_hex[b'D' as usize] = true;
23    is_hex[b'E' as usize] = true;
24    is_hex[b'F' as usize] = true;
25    is_hex
26};
27
28pub const IS_WHITESPACE: [bool; 256] = {
29    let mut is_whitespace = [false; 256];
30    is_whitespace[b' ' as usize] = true;
31    is_whitespace[b'\t' as usize] = true;
32    is_whitespace[b'\n' as usize] = true;
33    is_whitespace[b'\r' as usize] = true;
34    is_whitespace
35};
36
37pub const NEED_ESCAPE: [bool; 256] = {
38    let mut need_escape = [false; 256];
39    // Control characters: 00..=1F
40    need_escape[0] = true;
41    need_escape[1] = true;
42    need_escape[2] = true;
43    need_escape[3] = true;
44    need_escape[4] = true;
45    need_escape[5] = true;
46    need_escape[6] = true;
47    need_escape[7] = true;
48    need_escape[8] = true;
49    need_escape[9] = true;
50    need_escape[10] = true;
51    need_escape[11] = true;
52    need_escape[12] = true;
53    need_escape[13] = true;
54    need_escape[14] = true;
55    need_escape[15] = true;
56    need_escape[16] = true;
57    need_escape[17] = true;
58    need_escape[18] = true;
59    need_escape[19] = true;
60    need_escape[20] = true;
61    need_escape[21] = true;
62    need_escape[22] = true;
63    need_escape[23] = true;
64    need_escape[24] = true;
65    need_escape[25] = true;
66    need_escape[26] = true;
67    need_escape[27] = true;
68    need_escape[28] = true;
69    need_escape[29] = true;
70    need_escape[30] = true;
71    need_escape[31] = true;
72    // " and \
73    need_escape[b'"' as usize] = true;
74    need_escape[b'\\' as usize] = true;
75    need_escape
76};
77
78/// Decode a sequence of 4 hex characters into a u16 value.
79///
80/// # Panics
81///
82/// This function panics if the input is not a valid hex sequence.
83pub fn decode_hex_sequence(hexes: &[u8; 4]) -> u16 {
84    let mut value = 0;
85    for &hex in hexes {
86        value <<= 4;
87        value |= match hex {
88            b'0'..=b'9' => hex - b'0',
89            b'a'..=b'f' => hex - b'a' + 10,
90            b'A'..=b'F' => hex - b'A' + 10,
91            _ => unreachable!(),
92        } as u16;
93    }
94    value
95}
96
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98/// Represents a position where is the validator currently at.
99pub struct Position {
100    /// Line number, starting from `1``
101    pub line: usize,
102
103    /// Column number, starting from `0`, `0` mean did read any character from this `line`
104    pub column: usize,
105
106    /// Offset from the beginning of the entire input, starting from `0`
107    pub offset: usize,
108}
109
110impl Default for Position {
111    fn default() -> Self {
112        Position {
113            line: 1,
114            column: 0,
115            offset: 0,
116        }
117    }
118}
119
120impl std::fmt::Display for Position {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        write!(
123            f,
124            "line: {}, column: {}, offset: {}",
125            self.line, self.column, self.offset
126        )
127    }
128}
129
130/// An iterator that keeps track of the current line and column number.
131pub struct LineColumnIterator<'a, I: Iterator<Item = &'a u8>> {
132    /// The underlying iterator.
133    iter: I,
134
135    /// The current character.
136    ch: Option<&'a u8>,
137
138    /// The current position.
139    position: Position,
140}
141
142impl<'a, I: Iterator<Item = &'a u8>> LineColumnIterator<'a, I> {
143    pub fn new(iter: I) -> Self {
144        LineColumnIterator {
145            iter,
146            ch: None,
147            position: Position::default(),
148        }
149    }
150
151    /// Discard the current character.
152    ///
153    /// # Panics
154    ///
155    /// This function panics if there is no character to discard.
156    pub fn discard(&mut self) {
157        self.next().unwrap();
158    }
159
160    pub fn peek(&mut self) -> Option<&u8> {
161        if self.ch.is_some() {
162            return self.ch;
163        }
164
165        self.ch = self.iter.next();
166        self.ch
167    }
168
169    pub fn position(&self) -> Position {
170        self.position
171    }
172}
173
174impl<'a, I: Iterator<Item = &'a u8>> Iterator for LineColumnIterator<'a, I> {
175    type Item = &'a u8;
176
177    fn next(&mut self) -> Option<Self::Item> {
178        let ch = match self.ch {
179            Some(_) => {
180                let ch = self.ch;
181                self.ch = None;
182                ch
183            }
184            None => self.iter.next(),
185        };
186
187        match ch {
188            Some(b'\n') => {
189                self.position.line += 1;
190                self.position.column = 0;
191            }
192            Some(_) => {
193                self.position.column += 1;
194            }
195            None => return None,
196        }
197
198        self.position.offset += 1;
199        ch
200    }
201}