Skip to main content

sark_json/
scan.rs

1use memchr::memchr2;
2
3use crate::Result;
4use crate::error::Fail;
5
6pub struct Scan;
7
8pub(crate) struct StringSpan {
9    pub(crate) start: usize,
10    pub(crate) end: usize,
11    pub(crate) escaped: bool,
12    pub(crate) decoded_len: usize,
13}
14
15impl Scan {
16    pub fn ws(input: &[u8], idx: &mut usize) {
17        while *idx < input.len() && input[*idx].is_ascii_whitespace() {
18            *idx += 1;
19        }
20    }
21
22    pub fn eat_byte(input: &[u8], idx: &mut usize, want: u8) -> bool {
23        if *idx < input.len() && input[*idx] == want {
24            *idx += 1;
25            true
26        } else {
27            false
28        }
29    }
30
31    pub fn expect_byte(input: &[u8], idx: &mut usize, want: u8) -> Result<()> {
32        if Self::eat_byte(input, idx, want) {
33            return Ok(());
34        }
35        Err(Fail::bad())
36    }
37
38    pub fn expect_prop(input: &[u8], idx: &mut usize, first: bool, want: &[u8]) -> Result<()> {
39        Self::ws(input, idx);
40        if !first {
41            Self::expect_byte(input, idx, b',')?;
42            Self::ws(input, idx);
43        }
44        Self::expect_byte(input, idx, b'"')?;
45        let end = idx.saturating_add(want.len());
46        if input.get(*idx..end) != Some(want) {
47            return Err(Fail::bad());
48        }
49        *idx = end;
50        Self::expect_byte(input, idx, b'"')?;
51        Self::ws(input, idx);
52        Self::expect_byte(input, idx, b':')?;
53        Self::ws(input, idx);
54        Ok(())
55    }
56
57    pub fn seek_name(input: &[u8], idx: &mut usize, want: &[u8]) -> Result<()> {
58        let need = want.len() + 3;
59        while idx.saturating_add(need) <= input.len() {
60            if input[*idx] == b'"' {
61                let key_start = idx.saturating_add(1);
62                let key_end = key_start.saturating_add(want.len());
63                if input.get(key_start..key_end) == Some(want)
64                    && input.get(key_end) == Some(&b'"')
65                    && input.get(key_end + 1) == Some(&b':')
66                {
67                    *idx = key_end + 2;
68                    return Ok(());
69                }
70            }
71            *idx += 1;
72        }
73        Err(Fail::bad())
74    }
75
76    pub fn eat_null(input: &[u8], idx: &mut usize) -> bool {
77        if input.get(*idx..(*idx + 4)) == Some(b"null") {
78            *idx += 4;
79            true
80        } else {
81            false
82        }
83    }
84
85    pub fn skip_plain_string(input: &[u8], idx: &mut usize) -> Result<()> {
86        Self::expect_byte(input, idx, b'"')?;
87        let Some(relative) = memchr2(b'"', b'\\', &input[*idx..]) else {
88            *idx = input.len();
89            return Err(Fail::bad());
90        };
91        *idx += relative;
92        if input[*idx] == b'\\' {
93            return Err(Fail::bad());
94        }
95        *idx += 1;
96        Ok(())
97    }
98
99    pub fn skip_value(input: &[u8], idx: &mut usize) -> Result<()> {
100        Self::ws(input, idx);
101        if *idx >= input.len() {
102            return Err(Fail::bad());
103        }
104        match input[*idx] {
105            b'"' => {
106                let _ = Self::str_slice(input, idx)?;
107                Ok(())
108            }
109            b'{' => Self::skip_group(input, idx, b'{', b'}'),
110            b'[' => Self::skip_group(input, idx, b'[', b']'),
111            b't' => {
112                let _ = crate::parse::Parse::bool(input, idx)?;
113                Ok(())
114            }
115            b'f' => {
116                let _ = crate::parse::Parse::bool(input, idx)?;
117                Ok(())
118            }
119            b'n' => {
120                if input.get(*idx..(*idx + 4)) == Some(b"null") {
121                    *idx += 4;
122                    Ok(())
123                } else {
124                    Err(Fail::bad())
125                }
126            }
127            b'-' | b'0'..=b'9' => Self::skip_number(input, idx),
128            _ => Err(Fail::bad()),
129        }
130    }
131
132    fn skip_number(input: &[u8], idx: &mut usize) -> Result<()> {
133        let start = *idx;
134        let _ = Self::eat_byte(input, idx, b'-');
135        if !Self::skip_digits(input, idx) {
136            return Err(Fail::bad());
137        }
138        if Self::eat_byte(input, idx, b'.') && !Self::skip_digits(input, idx) {
139            return Err(Fail::bad());
140        }
141        if *idx < input.len() && (input[*idx] == b'e' || input[*idx] == b'E') {
142            *idx += 1;
143            if *idx < input.len() && (input[*idx] == b'+' || input[*idx] == b'-') {
144                *idx += 1;
145            }
146            if !Self::skip_digits(input, idx) {
147                return Err(Fail::bad());
148            }
149        }
150        if *idx == start {
151            return Err(Fail::bad());
152        }
153        Ok(())
154    }
155
156    fn skip_digits(input: &[u8], idx: &mut usize) -> bool {
157        let start = *idx;
158        while *idx < input.len() && input[*idx].is_ascii_digit() {
159            *idx += 1;
160        }
161        *idx != start
162    }
163
164    pub fn str_slice<'a>(input: &'a [u8], idx: &mut usize) -> Result<&'a [u8]> {
165        let span = Self::string_span(input, idx)?;
166        Ok(&input[span.start..span.end])
167    }
168
169    pub(crate) fn string_span(input: &[u8], idx: &mut usize) -> Result<StringSpan> {
170        Self::expect_byte(input, idx, b'"')?;
171        let start = *idx;
172        let Some(relative) = memchr2(b'"', b'\\', &input[start..]) else {
173            *idx = input.len();
174            return Err(Fail::bad());
175        };
176        *idx += relative;
177        if input[*idx] == b'"' {
178            let end = *idx;
179            *idx += 1;
180            return Ok(StringSpan {
181                start,
182                end,
183                escaped: false,
184                decoded_len: relative,
185            });
186        }
187
188        let mut escapes = 1;
189        *idx += 2;
190        while *idx < input.len() {
191            match input[*idx] {
192                b'\\' => {
193                    escapes += 1;
194                    *idx += 2;
195                }
196                b'"' => {
197                    let end = *idx;
198                    *idx += 1;
199                    return Ok(StringSpan {
200                        start,
201                        end,
202                        escaped: true,
203                        decoded_len: end - start - escapes,
204                    });
205                }
206                _ => {
207                    *idx += 1;
208                }
209            }
210        }
211        Err(Fail::bad())
212    }
213
214    fn skip_group(input: &[u8], idx: &mut usize, open: u8, close: u8) -> Result<()> {
215        Self::expect_byte(input, idx, open)?;
216        let mut depth = 1usize;
217        while *idx < input.len() {
218            match input[*idx] {
219                b'"' => {
220                    let _ = Self::str_slice(input, idx)?;
221                }
222                b'{' | b'[' => {
223                    if depth >= crate::MAX_DEPTH as usize {
224                        return Err(Fail::with("JSON nesting too deep"));
225                    }
226                    depth += 1;
227                    *idx += 1;
228                }
229                b @ (b'}' | b']') => {
230                    depth -= 1;
231                    *idx += 1;
232                    if depth == 0 {
233                        return if b == close { Ok(()) } else { Err(Fail::bad()) };
234                    }
235                }
236                _ => {
237                    *idx += 1;
238                }
239            }
240        }
241        Err(Fail::bad())
242    }
243}