1use std::ops;
2
3use o3::buffer::write::consume;
4
5use crate::{
6 Error, Nesting,
7 parsing::Depth,
8 segment::{Atom, ValueKind},
9 source::{outputs, string::String},
10};
11
12#[derive(Clone, Copy, Eq, PartialEq)]
13pub enum Taken {
14 Yes,
15 No,
16}
17
18pub trait Input {
19 fn ws(&self, index: &mut usize);
20 fn take_byte(&self, index: &mut usize, want: u8) -> Taken;
21 fn expect_byte(&self, index: &mut usize, want: u8) -> crate::Result<()>;
22 fn expect_prop(&self, index: &mut usize, first: bool, want: &[u8]) -> crate::Result<()>;
23 fn finish(&self, index: &mut usize) -> crate::Result<()>;
24 fn name(&self, index: &mut usize) -> crate::Result<Name<'_>>;
25 fn take_null(&self, index: &mut usize) -> Taken;
26 fn skip_value(&self, index: &mut usize) -> crate::Result<()>;
27 #[doc(hidden)]
28 fn skip_depth(&self, index: &mut usize, depth: Depth) -> crate::Result<()>;
29
30 #[doc(hidden)]
31 fn string_span(&self, index: &mut usize) -> crate::Result<StringSpan<'_>>;
32
33 fn parse_u64(&self, index: &mut usize) -> crate::Result<u64>;
34 fn parse_bool(&self, index: &mut usize) -> crate::Result<bool>;
35}
36
37impl Input for [u8] {
38 fn ws(&self, index: &mut usize) {
39 *index = ws_at(self, *index);
40 }
41
42 fn take_byte(&self, index: &mut usize, want: u8) -> Taken {
43 match byte_at(self, *index, want) {
44 Some(next) => {
45 *index = next;
46 Taken::Yes
47 }
48 None => Taken::No,
49 }
50 }
51
52 fn expect_byte(&self, index: &mut usize, want: u8) -> crate::Result<()> {
53 let next = byte_at(self, *index, want).ok_or(Error::Invalid)?;
54 *index = next;
55 Ok(())
56 }
57
58 fn expect_prop(&self, index: &mut usize, first: bool, want: &[u8]) -> crate::Result<()> {
59 let next = prop_at(self, *index, first, want)?;
60 *index = next;
61 Ok(())
62 }
63
64 fn finish(&self, index: &mut usize) -> crate::Result<()> {
65 let next = ws_at(self, *index);
66 if next != self.len() {
67 return Err(Error::Invalid);
68 }
69 *index = next;
70 Ok(())
71 }
72
73 fn name(&self, index: &mut usize) -> crate::Result<Name<'_>> {
74 let (span, next) = string_at(self, *index)?;
75 *index = next;
76 Ok(Name::new(span))
77 }
78
79 fn take_null(&self, index: &mut usize) -> Taken {
80 match null_at(self, *index) {
81 Some(next) => {
82 *index = next;
83 Taken::Yes
84 }
85 None => Taken::No,
86 }
87 }
88
89 fn skip_value(&self, index: &mut usize) -> crate::Result<()> {
90 self.skip_depth(index, Depth::ROOT)
91 }
92
93 fn skip_depth(&self, index: &mut usize, depth: Depth) -> crate::Result<()> {
94 let next = value_with(self, ws_at(self, *index), None, depth)?;
95 *index = next;
96 Ok(())
97 }
98
99 fn string_span(&self, index: &mut usize) -> crate::Result<StringSpan<'_>> {
100 let (span, next) = string_at(self, *index)?;
101 *index = next;
102 Ok(span)
103 }
104
105 fn parse_u64(&self, index: &mut usize) -> crate::Result<u64> {
106 let first = *self.get(*index).ok_or(Error::Invalid)?;
107 if first == b'-' {
108 return Err(Error::Invalid);
109 }
110 let (ValueKind::Unsigned(value), next) = atom_with::<true>(self, *index, first, None)?
111 else {
112 return Err(Error::Invalid);
113 };
114 *index = next;
115 Ok(value)
116 }
117
118 fn parse_bool(&self, index: &mut usize) -> crate::Result<bool> {
119 let (value, next) = bool_at(self, *index)?;
120 *index = next;
121 Ok(value)
122 }
123}
124
125pub fn parse_i64(input: &[u8], index: &mut usize) -> crate::Result<i64> {
126 let first = *input.get(*index).ok_or(Error::Invalid)?;
127 let (kind, next) = atom_with::<true>(input, *index, first, None)?;
128 let value = kind.i64()?;
129 *index = next;
130 Ok(value)
131}
132
133#[derive(Clone, Copy)]
134pub(crate) struct Content<'a>(&'a [u8]);
135
136impl<'a> Content<'a> {
137 pub(crate) const fn bytes(self) -> &'a [u8] {
138 self.0
139 }
140}
141
142#[doc(hidden)]
143pub struct StringSpan<'a> {
144 pub(crate) content: Content<'a>,
145 pub(crate) start: usize,
146 pub(crate) end: usize,
147 pub(crate) escaped: bool,
148 pub(crate) decoded_len: usize,
149}
150
151#[doc(hidden)]
152pub struct Name<'a> {
153 content: Content<'a>,
154 decoded_len: usize,
155 escaped: bool,
156}
157
158impl<'a> Name<'a> {
159 fn new(span: StringSpan<'a>) -> Self {
160 Self {
161 content: span.content,
162 decoded_len: span.decoded_len,
163 escaped: span.escaped,
164 }
165 }
166
167 pub const fn len(&self) -> usize {
168 self.decoded_len
169 }
170
171 pub const fn is_empty(&self) -> bool {
172 self.decoded_len == 0
173 }
174
175 pub fn is_equal(&self, expected: &[u8]) -> bool {
176 if !self.escaped {
177 return self.content.bytes() == expected;
178 }
179 if self.decoded_len != expected.len() {
180 return false;
181 }
182 outputs::Decoder::new(self.content).eq(expected.iter().copied())
183 }
184}
185
186fn prop_at(input: &[u8], index: usize, first: bool, want: &[u8]) -> crate::Result<usize> {
187 let mut next = ws_at(input, index);
188 if !first {
189 next = byte_at(input, next, b',').ok_or(Error::Invalid)?;
190 next = ws_at(input, next);
191 }
192 let (span, end) = string_at(input, next)?;
193 if !Name::new(span).is_equal(want) {
194 return Err(Error::Invalid);
195 }
196 next = ws_at(input, end);
197 next = byte_at(input, next, b':').ok_or(Error::Invalid)?;
198 Ok(ws_at(input, next))
199}
200
201#[derive(Clone, Copy)]
202struct Limit {
203 start: usize,
204 capacity: usize,
205 overhead: usize,
206}
207
208impl Limit {
209 fn check(self, end: usize) -> crate::Result<()> {
210 let len = (end - self.start).saturating_sub(self.overhead);
211 consume::Error::check(len, self.capacity).map_err(Error::Token)
212 }
213
214 fn scan_end(self, len: usize) -> usize {
215 len.min(self.start.saturating_add(self.capacity + self.overhead + 1))
216 }
217}
218
219fn check_limit(limit: Option<Limit>, end: usize) -> crate::Result<()> {
220 if let Some(limit) = limit {
221 limit.check(end)?;
222 }
223 Ok(())
224}
225
226pub(crate) fn inline_plain<'a>(
227 input: &'a [u8],
228 index: &mut usize,
229 capacity: u8,
230) -> crate::Result<Content<'a>> {
231 let limit = Limit {
232 start: *index,
233 capacity: usize::from(capacity),
234 overhead: 2,
235 };
236 let (span, end) = string_with(input, *index, Some(limit))?;
237 if span.escaped {
238 return Err(Error::Invalid);
239 }
240 *index = end;
241 Ok(span.content)
242}
243
244pub(crate) fn inline_depth(
245 input: &[u8],
246 index: &mut usize,
247 capacity: u8,
248 depth: Depth,
249) -> crate::Result<ops::Range<usize>> {
250 let start = ws_at(input, *index);
251 let limit = Limit {
252 start,
253 capacity: usize::from(capacity),
254 overhead: 0,
255 };
256 let end = value_with(input, start, Some(limit), depth)?;
257 *index = end;
258 Ok(start..end)
259}
260
261fn value_with(
262 input: &[u8],
263 index: usize,
264 limit: Option<Limit>,
265 depth: Depth,
266) -> crate::Result<usize> {
267 match input.get(index) {
268 Some(b'"') => string_with(input, index, limit).map(|(_, end)| end),
269 Some(&open) if matches!(open, b'{' | b'[') => group_at(input, index, open, limit, depth),
270 Some(&first) if matches!(first, b't' | b'f' | b'n' | b'-' | b'0'..=b'9') => {
271 atom_with::<false>(input, index, first, limit).map(|(_, end)| end)
272 }
273 _ => Err(Error::Invalid),
274 }
275}
276
277#[inline(always)]
278fn atom_with<const INTEGER: bool>(
279 input: &[u8],
280 index: usize,
281 first: u8,
282 limit: Option<Limit>,
283) -> crate::Result<(ValueKind, usize)> {
284 let mut atom = Atom::new(first, INTEGER)?;
285 let mut next = index;
286 while let Some(&byte) = input.get(next) {
287 if is_whitespace(byte) || matches!(byte, b',' | b'}' | b']') {
288 break;
289 }
290 atom = atom.step(byte)?;
291 if INTEGER && !matches!(atom, Atom::Number { value: Some(_), .. }) {
292 return Err(Error::Invalid);
293 }
294 next += 1;
295 check_limit(limit, next)?;
296 }
297 Ok((atom.finish()?, next))
298}
299
300fn string_at(input: &[u8], index: usize) -> crate::Result<(StringSpan<'_>, usize)> {
301 string_with(input, index, None)
302}
303
304fn string_with(
305 input: &[u8],
306 index: usize,
307 limit: Option<Limit>,
308) -> crate::Result<(StringSpan<'_>, usize)> {
309 let start = byte_at(input, index, b'"').ok_or(Error::Invalid)?;
310 check_limit(limit, start)?;
311 let mut string = String::new();
312 let mut next = start;
313 let scan_end = limit.map_or(input.len(), |limit| limit.scan_end(input.len()));
314 while next < input.len() {
315 let skipped = string.skip(unsafe { input.get_unchecked(next..scan_end) });
317 next += skipped.len();
318 check_limit(limit, next)?;
319 let Some(&byte) = input.get(next) else {
320 break;
321 };
322 let step = string.step(byte)?;
323 check_limit(limit, next + 1)?;
324 if step.is_none() {
325 let removed = string.removed();
326 return Ok((
327 StringSpan {
328 content: Content(unsafe { input.get_unchecked(start..next) }),
330 start,
331 end: next,
332 escaped: removed != 0,
333 decoded_len: next - start - removed,
334 },
335 next + 1,
336 ));
337 }
338 next += 1;
339 }
340 Err(Error::Invalid)
341}
342
343fn group_at(
344 input: &[u8],
345 index: usize,
346 open: u8,
347 limit: Option<Limit>,
348 depth: Depth,
349) -> crate::Result<usize> {
350 let mut next = byte_at(input, index, open).ok_or(Error::Invalid)?;
351 check_limit(limit, next)?;
352 let mut nesting = Nesting::start_depth(open, depth)?;
353 let scan_end = limit.map_or(input.len(), |limit| limit.scan_end(input.len()));
354 while next < input.len() {
355 let skipped = nesting.skip(unsafe { input.get_unchecked(next..scan_end) });
357 next += skipped.len();
358 check_limit(limit, next)?;
359 let Some(&byte) = input.get(next) else {
360 break;
361 };
362 next += 1;
363 let done = nesting.step(byte)?;
364 check_limit(limit, next)?;
365 if done {
366 return Ok(next);
367 }
368 }
369 Err(Error::Invalid)
370}
371
372fn bool_at(input: &[u8], index: usize) -> crate::Result<(bool, usize)> {
373 let first = *input.get(index).ok_or(Error::Invalid)?;
374 if !matches!(first, b't' | b'f') {
375 return Err(Error::Invalid);
376 }
377 let (kind, next) = atom_with::<false>(input, index, first, None)?;
378 match kind {
379 ValueKind::True => Ok((true, next)),
380 ValueKind::False => Ok((false, next)),
381 _ => Err(Error::Invalid),
382 }
383}
384
385pub(crate) const fn is_whitespace(byte: u8) -> bool {
386 matches!(byte, b' ' | b'\t' | b'\n' | b'\r')
387}
388
389fn ws_at(input: &[u8], index: usize) -> usize {
390 let mut next = index;
391 while input.get(next).is_some_and(|byte| is_whitespace(*byte)) {
392 next += 1;
393 }
394 next
395}
396
397fn byte_at(input: &[u8], index: usize, want: u8) -> Option<usize> {
398 if input.get(index) == Some(&want) {
399 index.checked_add(1)
400 } else {
401 None
402 }
403}
404
405fn null_at(input: &[u8], index: usize) -> Option<usize> {
406 let end = index.checked_add(4)?;
407 (input.get(index..end) == Some(b"null")).then_some(end)
408}
409
410const _: () = assert!(size_of::<Taken>() == size_of::<bool>());