rsonpath/input/
padding.rs

1use super::{SliceSeekable, MAX_BLOCK_SIZE};
2use crate::{string_pattern::StringPattern, JSON_SPACE_BYTE};
3
4pub(super) struct PaddedBlock {
5    bytes: [u8; MAX_BLOCK_SIZE],
6    padding_len: usize,
7}
8
9pub struct EndPaddedInput<'a> {
10    middle: &'a [u8],
11    last_block: &'a PaddedBlock,
12}
13
14pub struct TwoSidesPaddedInput<'a> {
15    first_block: &'a PaddedBlock,
16    middle: &'a [u8],
17    last_block: &'a PaddedBlock,
18}
19
20impl PaddedBlock {
21    #[allow(clippy::unused_self)] // This is nicer than using the constant everywhere.
22    pub(super) const fn len(&self) -> usize {
23        MAX_BLOCK_SIZE
24    }
25
26    pub(super) fn padding_len(&self) -> usize {
27        self.padding_len
28    }
29
30    pub(super) fn bytes(&self) -> &[u8] {
31        &self.bytes
32    }
33
34    pub(super) fn pad_first_block(bytes: &[u8]) -> Self {
35        assert!(bytes.len() <= MAX_BLOCK_SIZE);
36        let mut block_buf = [JSON_SPACE_BYTE; MAX_BLOCK_SIZE];
37        let block_start = MAX_BLOCK_SIZE - bytes.len();
38
39        block_buf[block_start..].copy_from_slice(bytes);
40
41        Self {
42            bytes: block_buf,
43            padding_len: block_start,
44        }
45    }
46
47    pub(super) fn pad_last_block(bytes: &[u8]) -> Self {
48        assert!(bytes.len() <= MAX_BLOCK_SIZE);
49        let mut last_block_buf = [JSON_SPACE_BYTE; MAX_BLOCK_SIZE];
50        let block_end = bytes.len();
51
52        last_block_buf[..block_end].copy_from_slice(bytes);
53
54        Self {
55            bytes: last_block_buf,
56            padding_len: MAX_BLOCK_SIZE - block_end,
57        }
58    }
59}
60
61impl SliceSeekable for EndPaddedInput<'_> {
62    #[cold]
63    #[inline(never)]
64    fn seek_backward(&self, from: usize, needle: u8) -> Option<usize> {
65        if from < self.middle.len() {
66            self.seek_backward_from_middle(from, needle)
67        } else {
68            self.seek_backward_from_last(from, needle)
69        }
70    }
71
72    #[cold]
73    #[inline(never)]
74    fn seek_forward<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
75        if from < self.middle.len() {
76            self.seek_forward_from_middle(from, needles)
77        } else {
78            self.seek_forward_from_last(from, needles)
79        }
80    }
81
82    #[cold]
83    #[inline(never)]
84    fn seek_non_whitespace_forward(&self, from: usize) -> Option<(usize, u8)> {
85        if from < self.middle.len() {
86            self.seek_non_whitespace_forward_from_middle(from)
87        } else {
88            self.seek_non_whitespace_forward_from_last(from)
89        }
90    }
91
92    #[cold]
93    #[inline(never)]
94    fn seek_non_whitespace_backward(&self, from: usize) -> Option<(usize, u8)> {
95        if from < self.middle.len() {
96            self.seek_non_whitespace_backward_from_middle(from)
97        } else {
98            self.seek_non_whitespace_backward_from_last(from)
99        }
100    }
101
102    #[cold]
103    #[inline(never)]
104    fn is_member_match(&self, from: usize, to: usize, member: &StringPattern) -> bool {
105        debug_assert!(from < to);
106        let other = member.quoted();
107        self.cold_member_match(other, from, to)
108    }
109}
110
111impl SliceSeekable for TwoSidesPaddedInput<'_> {
112    #[cold]
113    #[inline(never)]
114    fn seek_backward(&self, from: usize, needle: u8) -> Option<usize> {
115        if from < MAX_BLOCK_SIZE {
116            self.seek_backward_from_first(from, needle)
117        } else if from < self.middle.len() + MAX_BLOCK_SIZE {
118            self.seek_backward_from_middle(from, needle)
119        } else {
120            self.seek_backward_from_last(from, needle)
121        }
122    }
123
124    #[cold]
125    #[inline(never)]
126    fn seek_forward<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
127        if from < MAX_BLOCK_SIZE {
128            self.seek_forward_from_first(from, needles)
129        } else if from < self.middle.len() + MAX_BLOCK_SIZE {
130            self.seek_forward_from_middle(from, needles)
131        } else {
132            self.seek_forward_from_last(from, needles)
133        }
134    }
135
136    #[cold]
137    #[inline(never)]
138    fn seek_non_whitespace_forward(&self, from: usize) -> Option<(usize, u8)> {
139        if from < MAX_BLOCK_SIZE {
140            self.seek_non_whitespace_forward_from_first(from)
141        } else if from < self.middle.len() + MAX_BLOCK_SIZE {
142            self.seek_non_whitespace_forward_from_middle(from)
143        } else {
144            self.seek_non_whitespace_forward_from_last(from)
145        }
146    }
147
148    #[cold]
149    #[inline(never)]
150    fn seek_non_whitespace_backward(&self, from: usize) -> Option<(usize, u8)> {
151        if from < MAX_BLOCK_SIZE {
152            self.seek_non_whitespace_backward_from_first(from)
153        } else if from < self.middle.len() + MAX_BLOCK_SIZE {
154            self.seek_non_whitespace_backward_from_middle(from)
155        } else {
156            self.seek_non_whitespace_backward_from_last(from)
157        }
158    }
159
160    #[cold]
161    #[inline(never)]
162    fn is_member_match(&self, from: usize, to: usize, member: &StringPattern) -> bool {
163        debug_assert!(from < to);
164        let other = member.quoted();
165        self.cold_member_match(other, from, to)
166    }
167}
168
169impl<'a> EndPaddedInput<'a> {
170    pub(super) fn new(middle: &'a [u8], last: &'a PaddedBlock) -> Self {
171        Self {
172            middle,
173            last_block: last,
174        }
175    }
176
177    #[inline(always)]
178    pub(super) fn middle(&self) -> &'a [u8] {
179        self.middle
180    }
181
182    fn seek_backward_from_middle(&self, from: usize, needle: u8) -> Option<usize> {
183        debug_assert!(from < self.middle.len());
184        let bytes = self.middle;
185
186        seek_backward_impl(bytes, from, needle)
187    }
188
189    fn seek_backward_from_last(&self, from: usize, needle: u8) -> Option<usize> {
190        debug_assert!(from >= self.middle.len());
191        let bytes = &self.last_block.bytes;
192
193        seek_backward_impl(bytes, from - self.middle.len(), needle)
194            .map(|x| x + self.middle.len())
195            .or_else(|| self.seek_backward_from_middle(self.middle.len() - 1, needle))
196    }
197
198    fn seek_forward_from_middle<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
199        assert!(N > 0);
200        debug_assert!(from < self.middle.len());
201        let bytes = self.middle;
202
203        seek_forward_impl(bytes, from, needles).or_else(|| self.seek_forward_from_last(bytes.len(), needles))
204    }
205
206    fn seek_forward_from_last<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
207        assert!(N > 0);
208        debug_assert!(from >= self.middle.len());
209        let bytes = &self.last_block.bytes;
210
211        seek_forward_impl(bytes, from - self.middle.len(), needles).map(|(x, y)| (x + self.middle.len(), y))
212    }
213
214    fn seek_non_whitespace_forward_from_middle(&self, from: usize) -> Option<(usize, u8)> {
215        debug_assert!(from < self.middle.len());
216        let bytes = self.middle;
217
218        seek_non_whitespace_forward_impl(bytes, from)
219            .or_else(|| self.seek_non_whitespace_forward_from_last(bytes.len()))
220    }
221
222    fn seek_non_whitespace_forward_from_last(&self, from: usize) -> Option<(usize, u8)> {
223        debug_assert!(from >= self.middle.len());
224        let bytes = &self.last_block.bytes;
225
226        seek_non_whitespace_forward_impl(bytes, from - self.middle.len()).map(|(x, y)| (x + self.middle.len(), y))
227    }
228
229    fn seek_non_whitespace_backward_from_middle(&self, from: usize) -> Option<(usize, u8)> {
230        debug_assert!(from < self.middle.len());
231        let bytes = self.middle;
232
233        seek_non_whitespace_backward_impl(bytes, from)
234    }
235
236    fn seek_non_whitespace_backward_from_last(&self, from: usize) -> Option<(usize, u8)> {
237        debug_assert!(from >= self.middle.len());
238        let bytes = &self.last_block.bytes;
239
240        seek_non_whitespace_backward_impl(bytes, from - self.middle.len())
241            .map(|(x, y)| (x + self.middle.len(), y))
242            .or_else(|| self.seek_non_whitespace_backward_from_middle(self.middle.len() - 1))
243    }
244
245    pub(super) fn try_slice(&self, start: usize, len: usize) -> Option<&'a [u8]> {
246        debug_assert!(len < MAX_BLOCK_SIZE);
247
248        if start < self.middle.len() {
249            self.slice_middle(start, len)
250        } else {
251            self.slice_last(start, len)
252        }
253    }
254
255    fn slice_middle(&self, start: usize, len: usize) -> Option<&'a [u8]> {
256        Some(&self.middle[start..start + len])
257    }
258
259    fn slice_last(&self, start: usize, len: usize) -> Option<&'a [u8]> {
260        let start = start - self.middle.len();
261        (start < MAX_BLOCK_SIZE).then(|| &self.last_block.bytes[start..start + len])
262    }
263
264    /// Slice the entire input from `from` to `to` and return the part
265    /// from the middle, and the part from the last block. Either or both
266    /// may be empty when appropriate.
267    fn slice_parts(&self, from: usize, to: usize) -> (&[u8], &[u8]) {
268        use std::cmp::min;
269
270        let middle_from = min(from, self.middle.len());
271        let middle_to = min(to, self.middle.len());
272
273        let from = from.saturating_sub(self.middle.len());
274        let to = to.saturating_sub(self.middle.len());
275        let last_from = min(from, self.last_block.len());
276        let last_to = min(to, self.last_block.len());
277
278        (
279            &self.middle[middle_from..middle_to],
280            &self.last_block.bytes[last_from..last_to],
281        )
282    }
283
284    fn get_at(&self, idx: usize) -> Option<u8> {
285        if idx < self.middle.len() {
286            Some(self.middle[idx])
287        } else if idx < self.middle.len() + MAX_BLOCK_SIZE {
288            Some(self.last_block.bytes[idx - self.middle.len()])
289        } else {
290            None
291        }
292    }
293
294    fn cold_member_match(&self, other: &[u8], from: usize, to: usize) -> bool {
295        let (middle_self, last_self) = self.slice_parts(from, to);
296        let middle_other = &other[..middle_self.len()];
297        let last_other = &other[middle_self.len()..];
298        let preceding_char = from.checked_sub(1).and_then(|x| self.get_at(x));
299
300        middle_self == middle_other && last_self == last_other && preceding_char != Some(b'\\')
301    }
302}
303
304impl<'a> TwoSidesPaddedInput<'a> {
305    pub(super) fn new(first: &'a PaddedBlock, middle: &'a [u8], last: &'a PaddedBlock) -> Self {
306        Self {
307            first_block: first,
308            middle,
309            last_block: last,
310        }
311    }
312
313    #[inline(always)]
314    pub(super) fn middle(&self) -> &'a [u8] {
315        self.middle
316    }
317
318    fn seek_backward_from_first(&self, from: usize, needle: u8) -> Option<usize> {
319        debug_assert!(from < MAX_BLOCK_SIZE);
320        let bytes = &self.first_block.bytes;
321
322        seek_backward_impl(bytes, from, needle)
323    }
324
325    fn seek_backward_from_middle(&self, from: usize, needle: u8) -> Option<usize> {
326        debug_assert!(from >= MAX_BLOCK_SIZE);
327        let bytes = self.middle;
328
329        seek_backward_impl(bytes, from - MAX_BLOCK_SIZE, needle)
330            .map(|x| x + MAX_BLOCK_SIZE)
331            .or_else(|| self.seek_backward_from_first(MAX_BLOCK_SIZE - 1, needle))
332    }
333
334    fn seek_backward_from_last(&self, from: usize, needle: u8) -> Option<usize> {
335        debug_assert!(from >= self.middle.len() + MAX_BLOCK_SIZE);
336        let bytes = &self.last_block.bytes;
337
338        seek_backward_impl(bytes, from - self.middle.len() - MAX_BLOCK_SIZE, needle)
339            .map(|x| x + self.middle.len() + MAX_BLOCK_SIZE)
340            .or_else(|| {
341                if self.middle.is_empty() {
342                    self.seek_backward_from_first(MAX_BLOCK_SIZE - 1, needle)
343                } else {
344                    self.seek_backward_from_middle(self.middle.len() + MAX_BLOCK_SIZE - 1, needle)
345                }
346            })
347    }
348
349    fn seek_forward_from_first<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
350        assert!(N > 0);
351        debug_assert!(from < MAX_BLOCK_SIZE);
352        let bytes = &self.first_block.bytes;
353
354        seek_forward_impl(bytes, from, needles).or_else(|| {
355            if self.middle.is_empty() {
356                self.seek_forward_from_last(bytes.len(), needles)
357            } else {
358                self.seek_forward_from_middle(bytes.len(), needles)
359            }
360        })
361    }
362
363    fn seek_forward_from_middle<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
364        assert!(N > 0);
365        debug_assert!(from >= MAX_BLOCK_SIZE);
366        let bytes = self.middle;
367
368        seek_forward_impl(bytes, from - MAX_BLOCK_SIZE, needles)
369            .map(|(x, y)| (x + MAX_BLOCK_SIZE, y))
370            .or_else(|| self.seek_forward_from_last(bytes.len() + MAX_BLOCK_SIZE, needles))
371    }
372
373    fn seek_forward_from_last<const N: usize>(&self, from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
374        assert!(N > 0);
375        debug_assert!(from >= self.middle.len() + MAX_BLOCK_SIZE);
376        let bytes = &self.last_block.bytes;
377
378        seek_forward_impl(bytes, from - self.middle.len() - MAX_BLOCK_SIZE, needles)
379            .map(|(x, y)| (x + self.middle.len() + MAX_BLOCK_SIZE, y))
380    }
381
382    fn seek_non_whitespace_forward_from_first(&self, from: usize) -> Option<(usize, u8)> {
383        debug_assert!(from < MAX_BLOCK_SIZE);
384        let bytes = &self.first_block.bytes;
385
386        seek_non_whitespace_forward_impl(bytes, from).or_else(|| {
387            if self.middle.is_empty() {
388                self.seek_non_whitespace_forward_from_last(bytes.len())
389            } else {
390                self.seek_non_whitespace_forward_from_middle(bytes.len())
391            }
392        })
393    }
394
395    fn seek_non_whitespace_forward_from_middle(&self, from: usize) -> Option<(usize, u8)> {
396        debug_assert!(from >= MAX_BLOCK_SIZE);
397        let bytes = self.middle;
398
399        seek_non_whitespace_forward_impl(bytes, from - MAX_BLOCK_SIZE)
400            .map(|(x, y)| (x + MAX_BLOCK_SIZE, y))
401            .or_else(|| self.seek_non_whitespace_forward_from_last(bytes.len() + MAX_BLOCK_SIZE))
402    }
403
404    fn seek_non_whitespace_forward_from_last(&self, from: usize) -> Option<(usize, u8)> {
405        debug_assert!(from >= self.middle.len() + MAX_BLOCK_SIZE);
406        let bytes = &self.last_block.bytes;
407
408        seek_non_whitespace_forward_impl(bytes, from - self.middle.len() - MAX_BLOCK_SIZE)
409            .map(|(x, y)| (x + self.middle.len() + MAX_BLOCK_SIZE, y))
410    }
411
412    fn seek_non_whitespace_backward_from_first(&self, from: usize) -> Option<(usize, u8)> {
413        debug_assert!(from < MAX_BLOCK_SIZE);
414        let bytes = &self.first_block.bytes;
415
416        seek_non_whitespace_backward_impl(bytes, from)
417    }
418
419    fn seek_non_whitespace_backward_from_middle(&self, from: usize) -> Option<(usize, u8)> {
420        debug_assert!(from >= MAX_BLOCK_SIZE);
421        let bytes = self.middle;
422
423        seek_non_whitespace_backward_impl(bytes, from - MAX_BLOCK_SIZE)
424            .map(|(x, y)| (x + MAX_BLOCK_SIZE, y))
425            .or_else(|| self.seek_non_whitespace_backward_from_first(MAX_BLOCK_SIZE - 1))
426    }
427
428    fn seek_non_whitespace_backward_from_last(&self, from: usize) -> Option<(usize, u8)> {
429        debug_assert!(from >= self.middle.len() + MAX_BLOCK_SIZE);
430        let bytes = &self.last_block.bytes;
431
432        seek_non_whitespace_backward_impl(bytes, from - self.middle.len() - MAX_BLOCK_SIZE)
433            .map(|(x, y)| (x + self.middle.len() + MAX_BLOCK_SIZE, y))
434            .or_else(|| {
435                if self.middle.is_empty() {
436                    self.seek_non_whitespace_backward_from_first(MAX_BLOCK_SIZE - 1)
437                } else {
438                    self.seek_non_whitespace_backward_from_middle(self.middle.len() + MAX_BLOCK_SIZE - 1)
439                }
440            })
441    }
442
443    pub(super) fn try_slice(&self, start: usize, len: usize) -> Option<&'a [u8]> {
444        debug_assert!(len < MAX_BLOCK_SIZE);
445
446        if start < MAX_BLOCK_SIZE {
447            Some(self.slice_first(start, len))
448        } else if start < self.middle.len() + MAX_BLOCK_SIZE {
449            Some(self.slice_middle(start, len))
450        } else {
451            self.slice_last(start, len)
452        }
453    }
454
455    fn slice_first(&self, start: usize, len: usize) -> &'a [u8] {
456        &self.first_block.bytes[start..start + len]
457    }
458
459    fn slice_middle(&self, start: usize, len: usize) -> &'a [u8] {
460        let start = start - MAX_BLOCK_SIZE;
461        &self.middle[start..start + len]
462    }
463
464    fn slice_last(&self, start: usize, len: usize) -> Option<&'a [u8]> {
465        let start = start - self.middle.len() - MAX_BLOCK_SIZE;
466        (start < MAX_BLOCK_SIZE).then(|| &self.last_block.bytes[start..start + len])
467    }
468
469    /// Slice the entire input from `from` to `to` and return the part
470    /// from the first block, from the middle, and the part from the last block.
471    /// Any and all of them may be empty when appropriate.
472    fn slice_parts(&self, from: usize, to: usize) -> (&[u8], &[u8], &[u8]) {
473        use std::cmp::min;
474
475        let first_from = min(from, MAX_BLOCK_SIZE);
476        let first_to = min(to, MAX_BLOCK_SIZE);
477
478        let from = from.saturating_sub(MAX_BLOCK_SIZE);
479        let to = to.saturating_sub(MAX_BLOCK_SIZE);
480        let middle_from = min(from, self.middle.len());
481        let middle_to = min(to, self.middle.len());
482
483        let from = from.saturating_sub(self.middle.len());
484        let to = to.saturating_sub(self.middle.len());
485        let last_from = min(from, self.last_block.len());
486        let last_to = min(to, self.last_block.len());
487
488        (
489            &self.first_block.bytes[first_from..first_to],
490            &self.middle[middle_from..middle_to],
491            &self.last_block.bytes[last_from..last_to],
492        )
493    }
494
495    fn get_at(&self, idx: usize) -> Option<u8> {
496        if idx < MAX_BLOCK_SIZE {
497            Some(self.first_block.bytes[idx])
498        } else if idx < self.middle.len() + MAX_BLOCK_SIZE {
499            Some(self.middle[idx - MAX_BLOCK_SIZE])
500        } else if idx < self.middle.len() + 2 * MAX_BLOCK_SIZE {
501            Some(self.last_block.bytes[idx - MAX_BLOCK_SIZE - self.middle.len()])
502        } else {
503            None
504        }
505    }
506
507    fn cold_member_match(&self, other: &[u8], from: usize, to: usize) -> bool {
508        let (first_self, middle_self, last_self) = self.slice_parts(from, to);
509        let first_other = &other[..first_self.len()];
510        let middle_other = &other[first_self.len()..first_self.len() + middle_self.len()];
511        let last_other = &other[first_self.len() + middle_self.len()..];
512        let preceding_char = from.checked_sub(1).and_then(|x| self.get_at(x));
513
514        first_self == first_other
515            && middle_self == middle_other
516            && last_self == last_other
517            && preceding_char != Some(b'\\')
518    }
519}
520
521#[inline(always)]
522fn seek_backward_impl(bytes: &[u8], from: usize, needle: u8) -> Option<usize> {
523    let mut idx = from;
524    assert!(idx < bytes.len());
525
526    loop {
527        if bytes[idx] == needle {
528            return Some(idx);
529        }
530        if idx == 0 {
531            return None;
532        }
533        idx -= 1;
534    }
535}
536
537#[inline(always)]
538fn seek_forward_impl<const N: usize>(bytes: &[u8], from: usize, needles: [u8; N]) -> Option<(usize, u8)> {
539    let mut idx = from;
540    if idx >= bytes.len() {
541        return None;
542    }
543
544    loop {
545        let b = bytes[idx];
546        if needles.contains(&b) {
547            return Some((idx, b));
548        }
549        idx += 1;
550        if idx == bytes.len() {
551            return None;
552        }
553    }
554}
555
556#[inline(always)]
557fn seek_non_whitespace_forward_impl(bytes: &[u8], from: usize) -> Option<(usize, u8)> {
558    let mut idx = from;
559    if idx >= bytes.len() {
560        return None;
561    }
562
563    loop {
564        let b = bytes[idx];
565        if !b.is_ascii_whitespace() {
566            return Some((idx, b));
567        }
568        idx += 1;
569        if idx == bytes.len() {
570            return None;
571        }
572    }
573}
574
575#[inline(always)]
576fn seek_non_whitespace_backward_impl(bytes: &[u8], from: usize) -> Option<(usize, u8)> {
577    let mut idx = from;
578    if idx >= bytes.len() {
579        return None;
580    }
581
582    loop {
583        let b = bytes[idx];
584        if !b.is_ascii_whitespace() {
585            return Some((idx, b));
586        }
587        if idx == 0 {
588            return None;
589        }
590        idx -= 1;
591    }
592}
593
594#[cfg(test)]
595mod test {
596    use super::*;
597    use pretty_assertions::assert_eq;
598
599    #[test]
600    fn on_empty_bytes_is_all_whitespace() {
601        let result = PaddedBlock::pad_last_block(&[]);
602
603        assert_eq!(result.bytes, [JSON_SPACE_BYTE; MAX_BLOCK_SIZE]);
604    }
605
606    #[test]
607    fn on_bytes_smaller_than_full_block_gives_entire_block() {
608        let bytes = r#"{"test":42}"#.as_bytes();
609
610        let result = PaddedBlock::pad_last_block(bytes);
611
612        assert_eq!(&result.bytes[0..11], bytes);
613        assert_eq!(&result.bytes[11..], [JSON_SPACE_BYTE; MAX_BLOCK_SIZE - 11]);
614    }
615
616    #[test]
617    fn on_bytes_equal_to_full_block_does_not_change_block() {
618        let bytes = [42; MAX_BLOCK_SIZE];
619
620        let result = PaddedBlock::pad_last_block(&bytes);
621
622        assert_eq!(result.bytes, bytes);
623    }
624
625    mod two_sided_padded_input {
626        mod seek_forward_1 {
627            use crate::input::{
628                padding::{PaddedBlock, TwoSidesPaddedInput},
629                SliceSeekable,
630            };
631            use pretty_assertions::assert_eq;
632            use std::iter;
633
634            #[test]
635            fn in_empty_slice_returns_none() {
636                let input = TwoSidesPaddedInput {
637                    first_block: &PaddedBlock::pad_first_block(&[]),
638                    middle: &[],
639                    last_block: &PaddedBlock::pad_last_block(&[]),
640                };
641
642                let result = input.seek_forward(0, [0]);
643
644                assert_eq!(result, None);
645            }
646
647            #[test]
648            fn seeking_from_first_block_from_needle_returns_that() {
649                let input = TwoSidesPaddedInput {
650                    first_block: &PaddedBlock::pad_first_block(r#"{"seek": 42}"#.as_bytes()),
651                    middle: &[],
652                    last_block: &PaddedBlock::pad_last_block(&[]),
653                };
654
655                let result = input.seek_forward(123, [b':']);
656
657                assert_eq!(result, Some((123, b':')));
658            }
659
660            #[test]
661            fn seeking_from_middle_block_from_needle_returns_that() {
662                let input = TwoSidesPaddedInput {
663                    first_block: &PaddedBlock::pad_first_block(&[]),
664                    middle: r#"{"seek": 42}"#.as_bytes(),
665                    last_block: &PaddedBlock::pad_last_block(&[]),
666                };
667
668                let result = input.seek_forward(128 + 7, [b':']);
669
670                assert_eq!(result, Some((128 + 7, b':')));
671            }
672
673            #[test]
674            fn seeking_from_last_block_from_needle_returns_that() {
675                let input = TwoSidesPaddedInput {
676                    first_block: &PaddedBlock::pad_first_block(&[]),
677                    middle: &iter::repeat(b' ').take(256).collect::<Vec<_>>(),
678                    last_block: &PaddedBlock::pad_last_block(r#"{"seek": 42}"#.as_bytes()),
679                };
680
681                let result = input.seek_forward(128 + 256 + 7, [b':']);
682
683                assert_eq!(result, Some((128 + 256 + 7, b':')));
684            }
685
686            #[test]
687            fn seeking_from_first_block_from_not_needle_returns_next_needle() {
688                let input = TwoSidesPaddedInput {
689                    first_block: &PaddedBlock::pad_first_block(r"seek: \t\n42}".as_bytes()),
690                    middle: &[],
691                    last_block: &PaddedBlock::pad_last_block(&[]),
692                };
693
694                let result = input.seek_forward(119, [b'2']);
695
696                assert_eq!(result, Some((126, b'2')));
697            }
698
699            #[test]
700            fn seeking_from_middle_block_from_not_needle_returns_next_needle() {
701                let input = TwoSidesPaddedInput {
702                    first_block: &PaddedBlock::pad_first_block(&[]),
703                    middle: r"seek: \t\n42}".as_bytes(),
704                    last_block: &PaddedBlock::pad_last_block(&[]),
705                };
706
707                let result = input.seek_forward(128 + 5, [b'2']);
708
709                assert_eq!(result, Some((128 + 11, b'2')));
710            }
711
712            #[test]
713            fn seeking_from_last_block_from_not_needle_returns_next_needle() {
714                let input = TwoSidesPaddedInput {
715                    first_block: &PaddedBlock::pad_first_block(&[]),
716                    middle: &iter::repeat(b' ').take(256).collect::<Vec<_>>(),
717                    last_block: &PaddedBlock::pad_last_block(r"seek: \t\n42}".as_bytes()),
718                };
719
720                let result = input.seek_forward(128 + 256 + 5, [b'2']);
721
722                assert_eq!(result, Some((128 + 256 + 11, b'2')));
723            }
724
725            #[test]
726            fn seeking_from_first_block_from_not_needle_when_there_is_no_needle_returns_none() {
727                let bytes = "seek: \t\n42}".as_bytes();
728
729                let result = bytes.seek_forward(5, [b'3']);
730
731                assert_eq!(result, None);
732            }
733        }
734
735        mod seek_forward_2 {
736            use crate::input::{
737                padding::{PaddedBlock, TwoSidesPaddedInput},
738                SliceSeekable,
739            };
740            use pretty_assertions::assert_eq;
741
742            #[test]
743            fn in_empty_input_returns_none() {
744                let input = TwoSidesPaddedInput {
745                    first_block: &PaddedBlock::pad_first_block(&[]),
746                    middle: &[],
747                    last_block: &PaddedBlock::pad_last_block(&[]),
748                };
749
750                let result = input.seek_forward(0, [0, 1]);
751
752                assert_eq!(result, None);
753            }
754
755            #[test]
756            fn seeking_from_needle_1_returns_that() {
757                let bytes = r#"{"seek": 42}"#.as_bytes();
758
759                let result = bytes.seek_forward(7, [b':', b'4']);
760
761                assert_eq!(result, Some((7, b':')));
762            }
763
764            #[test]
765            fn seeking_from_needle_2_returns_that() {
766                let bytes = r#"{"seek": 42}"#.as_bytes();
767
768                let result = bytes.seek_forward(7, [b'4', b':']);
769
770                assert_eq!(result, Some((7, b':')));
771            }
772
773            #[test]
774            fn seeking_from_not_needle_when_next_is_needle_1_returns_that() {
775                let bytes = "seek: \t\n42}".as_bytes();
776
777                let result = bytes.seek_forward(5, [b'4', b'2']);
778
779                assert_eq!(result, Some((8, b'4')));
780            }
781
782            #[test]
783            fn seeking_from_not_needle_when_next_is_needle_2_returns_that() {
784                let bytes = "seek: \t\n42}".as_bytes();
785
786                let result = bytes.seek_forward(5, [b'2', b'4']);
787
788                assert_eq!(result, Some((8, b'4')));
789            }
790
791            #[test]
792            fn seeking_from_not_needle_when_there_is_no_needle_returns_none() {
793                let bytes = "seek: \t\n42}".as_bytes();
794
795                let result = bytes.seek_forward(5, [b'3', b'0']);
796
797                assert_eq!(result, None);
798            }
799        }
800
801        mod seek_backward {
802            use crate::input::{
803                padding::{PaddedBlock, TwoSidesPaddedInput},
804                SliceSeekable,
805            };
806            use pretty_assertions::assert_eq;
807
808            #[test]
809            fn in_empty_slice_returns_none() {
810                let input = TwoSidesPaddedInput {
811                    first_block: &PaddedBlock::pad_first_block(&[]),
812                    middle: &[],
813                    last_block: &PaddedBlock::pad_last_block(&[]),
814                };
815
816                let result = input.seek_non_whitespace_forward(0);
817
818                assert_eq!(result, None);
819            }
820
821            #[test]
822            fn seeking_from_needle_returns_that() {
823                let input = TwoSidesPaddedInput {
824                    first_block: &PaddedBlock::pad_first_block(&[]),
825                    middle: r#"{"seek": 42}"#.as_bytes(),
826                    last_block: &PaddedBlock::pad_last_block(&[]),
827                };
828
829                let result = input.seek_backward(136, b':');
830
831                assert_eq!(result, Some(135));
832            }
833
834            #[test]
835            fn seeking_from_not_needle_when_previous_is_needle_returns_that() {
836                let input = TwoSidesPaddedInput {
837                    first_block: &PaddedBlock::pad_first_block(&[]),
838                    middle: "seek: \t\n42}".as_bytes(),
839                    last_block: &PaddedBlock::pad_last_block(&[]),
840                };
841
842                let result = input.seek_backward(137, b'4');
843
844                assert_eq!(result, Some(136));
845            }
846
847            #[test]
848            fn seeking_from_not_needle_when_there_is_no_needle_returns_none() {
849                let input = TwoSidesPaddedInput {
850                    first_block: &PaddedBlock::pad_first_block(&[]),
851                    middle: "seek: \t\n42}".as_bytes(),
852                    last_block: &PaddedBlock::pad_last_block(&[]),
853                };
854
855                let result = input.seek_backward(138, b'3');
856
857                assert_eq!(result, None);
858            }
859        }
860
861        mod seek_non_whitespace_forward {
862            use crate::input::{
863                padding::{PaddedBlock, TwoSidesPaddedInput},
864                SliceSeekable,
865            };
866            use pretty_assertions::assert_eq;
867            use std::iter;
868
869            #[test]
870            fn in_empty_slice_returns_none() {
871                let input = TwoSidesPaddedInput {
872                    first_block: &PaddedBlock::pad_first_block(&[]),
873                    middle: &[],
874                    last_block: &PaddedBlock::pad_last_block(&[]),
875                };
876
877                let result = input.seek_non_whitespace_forward(0);
878
879                assert_eq!(result, None);
880            }
881
882            #[test]
883            fn seeking_from_first_block_from_non_whitespace_returns_that() {
884                let input = TwoSidesPaddedInput {
885                    first_block: &PaddedBlock::pad_first_block(r#"{"seek": 42}"#.as_bytes()),
886                    middle: &[],
887                    last_block: &PaddedBlock::pad_last_block(&[]),
888                };
889
890                let result = input.seek_non_whitespace_forward(123);
891
892                assert_eq!(result, Some((123, b':')));
893            }
894
895            #[test]
896            fn seeking_from_middle_block_from_non_whitespace_returns_that() {
897                let input = TwoSidesPaddedInput {
898                    first_block: &PaddedBlock::pad_first_block(&[]),
899                    middle: r#"{"seek": 42}"#.as_bytes(),
900                    last_block: &PaddedBlock::pad_last_block(&[]),
901                };
902
903                let result = input.seek_non_whitespace_forward(128 + 7);
904
905                assert_eq!(result, Some((128 + 7, b':')));
906            }
907
908            #[test]
909            fn seeking_from_last_block_from_non_whitespace_returns_that() {
910                let input = TwoSidesPaddedInput {
911                    first_block: &PaddedBlock::pad_first_block(&[]),
912                    middle: &iter::repeat(b' ').take(256).collect::<Vec<_>>(),
913                    last_block: &PaddedBlock::pad_last_block(r#"{"seek": 42}"#.as_bytes()),
914                };
915
916                let result = input.seek_non_whitespace_forward(128 + 256 + 7);
917
918                assert_eq!(result, Some((128 + 256 + 7, b':')));
919            }
920
921            #[test]
922            fn seeking_from_whitespace_returns_next_non_whitespace() {
923                let bytes = "seek: \t\n42}".as_bytes();
924
925                let result = bytes.seek_non_whitespace_forward(5);
926
927                assert_eq!(result, Some((8, b'4')));
928            }
929
930            #[test]
931            fn seeking_from_whitespace_when_there_is_no_more_non_whitespace_returns_none() {
932                let bytes = "seek: \t\n ".as_bytes();
933
934                let result = bytes.seek_non_whitespace_forward(5);
935
936                assert_eq!(result, None);
937            }
938        }
939    }
940}