xfind/
finder.rs

1//! Provides forward and backward substring searchers that operate on stream.
2use crate::buffer::{Buffer, BufferRev};
3use memchr::memmem;
4use std::io::{self, Read, Seek, SeekFrom};
5
6/// Returns the index of the first occurrence of the given needle in the stream.
7///
8/// # Examples
9///
10/// ```
11/// use std::io::{self, Cursor};
12///
13/// fn main() -> io::Result<()> {
14///     let mut stream = Cursor::new(b"rusty rust");
15///
16///     let pos = xfind::find(b"rust", &mut stream).transpose()?;
17///     assert_eq!(pos, Some(0));
18///
19///     Ok(())
20/// }
21/// ```
22pub fn find<R>(needle: &[u8], rdr: &mut R) -> Option<io::Result<usize>>
23where
24    R: Read,
25{
26    FindIter::new_with_needle(rdr, needle).next()
27}
28
29/// Returns the index of the last occurrence of the given needle in the stream.
30///
31/// # Examples
32///
33/// ```
34/// use std::io::{self, Cursor};
35///
36/// fn main() -> io::Result<()> {
37///     let mut stream = Cursor::new(b"rusty rust");
38///
39///     let pos = xfind::rfind(b"rust", &mut stream).transpose()?;
40///     assert_eq!(pos, Some(6));
41///
42///     Ok(())
43/// }
44/// ```
45pub fn rfind<R>(needle: &[u8], rdr: &mut R) -> Option<io::Result<usize>>
46where
47    R: Read + Seek,
48{
49    match FindRevIter::new_with_needle(rdr, needle) {
50        Ok(mut iter) => iter.next(),
51        Err(e) => Some(Err(e)),
52    }
53}
54
55/// Returns an iterator over all occurrences of the given needle in the stream.
56///
57/// # Examples
58///
59/// ```
60/// use std::io::{self, Cursor};
61///
62/// fn main() -> io::Result<()> {
63///     let mut stream = Cursor::new(b"rusty rust");
64///
65///     let mut iter = xfind::find_iter(b"rust", &mut stream);
66///     assert_eq!(iter.next().transpose()?, Some(0));
67///     assert_eq!(iter.next().transpose()?, Some(6));
68///     assert_eq!(iter.next().transpose()?, None);
69///
70///     Ok(())
71/// }
72/// ```
73pub fn find_iter<'n, 's, R>(
74    needle: &'n [u8],
75    rdr: &'s mut R,
76) -> FindIter<'n, 's, R>
77where
78    R: Read,
79{
80    FindIter::new_with_needle(rdr, needle)
81}
82
83/// Returns a reverse iterator over all occurrences of the given needle in the stream.
84///
85/// # Errors
86///
87/// Returns an I/O error if seeking to the end of the stream failed.
88///
89/// # Panics
90///
91/// Panics if the length of the stream is greater than `usize::MAX`.
92///
93/// # Examples
94///
95/// ```
96/// use std::io::{self, Cursor};
97///
98/// fn main() -> io::Result<()> {
99///     let mut stream = Cursor::new(b"rusty rust");
100///
101///     let mut iter = xfind::rfind_iter(b"rust", &mut stream)?;
102///     assert_eq!(iter.next().transpose()?, Some(6));
103///     assert_eq!(iter.next().transpose()?, Some(0));
104///     assert_eq!(iter.next().transpose()?, None);
105///
106///     Ok(())
107/// }
108/// ```
109pub fn rfind_iter<'n, 's, R>(
110    needle: &'n [u8],
111    rdr: &'s mut R,
112) -> io::Result<FindRevIter<'n, 's, R>>
113where
114    R: Read + Seek,
115{
116    FindRevIter::new_with_needle(rdr, needle)
117}
118
119/// A substring searcher for stream searches.
120#[derive(Clone, Debug)]
121pub struct StreamFinder<'n> {
122    /// The string we want to search.
123    needle: &'n [u8],
124}
125
126impl<'n> StreamFinder<'n> {
127    /// Creates a new `StreamFinder` for the given needle.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use xfind::StreamFinder;
133    ///
134    /// let finder = StreamFinder::new(b"rust");
135    /// ```
136    pub fn new(needle: &'n [u8]) -> StreamFinder<'n> {
137        StreamFinder { needle }
138    }
139
140    /// Returns the needle that this finder searches for.
141    ///
142    /// # Examples
143    ///
144    /// ```
145    /// use xfind::StreamFinder;
146    ///
147    /// let finder = StreamFinder::new(b"rust");
148    /// assert_eq!(finder.needle(), b"rust");
149    /// ```
150    pub fn needle(&self) -> &[u8] {
151        self.needle
152    }
153
154    /// Returns the index of the first occurrence of the given needle in the stream.
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use std::io::{self, Cursor};
160    /// use xfind::StreamFinder;
161    ///
162    /// fn main() -> io::Result<()> {
163    ///     let mut stream = Cursor::new(b"rusty rust");
164    ///     let finder = StreamFinder::new(b"rust");
165    ///
166    ///     let pos = finder.find(&mut stream).transpose()?;
167    ///     assert_eq!(pos, Some(0));
168    ///
169    ///     Ok(())
170    /// }
171    /// ```
172    pub fn find<R: Read>(&self, rdr: &mut R) -> Option<io::Result<usize>> {
173        self.find_iter(rdr).next()
174    }
175
176    /// Returns the index of the last occurrence of the given needle in the stream.
177    ///
178    /// # Panics
179    ///
180    /// Panics if the length of the stream is greater than `usize::MAX`.
181    ///
182    /// # Examples
183    ///
184    /// ```
185    /// use std::io::{self, Cursor};
186    /// use xfind::StreamFinder;
187    ///
188    /// fn main() -> io::Result<()> {
189    ///     let mut stream = Cursor::new(b"rusty rust");
190    ///     let finder = StreamFinder::new(b"rust");
191    ///
192    ///     let pos = finder.rfind(&mut stream).transpose()?;
193    ///     assert_eq!(pos, Some(6));
194    ///
195    ///     Ok(())
196    /// }
197    /// ```
198    pub fn rfind<R: Read + Seek>(
199        &self,
200        rdr: &mut R,
201    ) -> Option<io::Result<usize>> {
202        match self.rfind_iter(rdr) {
203            Ok(mut iter) => iter.next(),
204            Err(e) => Some(Err(e)),
205        }
206    }
207
208    /// Returns an iterator over all occurrences of the given needle in the stream.
209    ///
210    /// # Examples
211    ///
212    /// ```
213    /// use std::io::{self, Cursor};
214    /// use xfind::StreamFinder;
215    ///
216    /// fn main() -> io::Result<()> {
217    ///     let mut stream = Cursor::new(b"rusty rust");
218    ///     let finder = StreamFinder::new(b"rust");
219    ///
220    ///     let mut iter = finder.find_iter(&mut stream);
221    ///     assert_eq!(iter.next().transpose()?, Some(0));
222    ///     assert_eq!(iter.next().transpose()?, Some(6));
223    ///     assert_eq!(iter.next().transpose()?, None);
224    ///
225    ///     Ok(())
226    /// }
227    /// ```
228    pub fn find_iter<'s, R: Read>(
229        &'n self,
230        rdr: &'s mut R,
231    ) -> FindIter<'n, 's, R> {
232        FindIter::new(rdr, self)
233    }
234
235    /// Returns a reverse iterator over all occurrences of the given needle in the stream.
236    ///
237    /// # Errors
238    ///
239    /// Returns an I/O error if seeking to the end of the stream failed.
240    ///
241    /// # Panics
242    ///
243    /// Panics if the length of the stream is greater than `usize::MAX`.
244    ///
245    /// # Examples
246    ///
247    /// ```
248    /// use std::io::{self, Cursor};
249    /// use xfind::StreamFinder;
250    ///
251    /// fn main() -> io::Result<()> {
252    ///     let mut stream = Cursor::new(b"rusty rust");
253    ///     let finder = StreamFinder::new(b"rust");
254    ///
255    ///     let mut iter = finder.rfind_iter(&mut stream)?;
256    ///     assert_eq!(iter.next().transpose()?, Some(6));
257    ///     assert_eq!(iter.next().transpose()?, Some(0));
258    ///     assert_eq!(iter.next().transpose()?, None);
259    ///
260    ///     Ok(())
261    /// }
262    /// ```
263    pub fn rfind_iter<'s, R: Read + Seek>(
264        &'n self,
265        rdr: &'s mut R,
266    ) -> io::Result<FindRevIter<'n, 's, R>> {
267        FindRevIter::new(rdr, self)
268    }
269}
270
271/// A forward iterator over all non-overlapping occurrences of a substring in a stream.
272///
273/// Matches are reported by the byte offset at which they begin.
274#[derive(Debug)]
275pub struct FindIter<'n, 's, R: Read> {
276    /// The stream source we read from.
277    rdr: &'s mut R,
278    /// The needle we search for.
279    needle: &'n [u8],
280    /// A fixed size buffer that we actually search for. It must be big enough to hold the needle.
281    buf: Buffer,
282    /// The current position at which to start the next search in `self.buf`.
283    search_pos: usize,
284    /// The absolute position of `search_pos` in the stream.
285    stream_pos: usize,
286    /// The position we report to the caller.
287    report_pos: usize,
288}
289
290/// A backward iterator over all non-overlapping occurrences of a substring in a stream.
291///
292/// Matches are reported by the byte offset at which they begin.
293#[derive(Debug)]
294pub struct FindRevIter<'n, 's, R: Read + Seek> {
295    /// The stream source we read from.
296    rdr: &'s mut R,
297    /// The needle we search for.
298    needle: &'n [u8],
299    /// A fixed size buffer that we actually search for. It must be big enough to hold the needle.
300    buf: BufferRev,
301    /// The current position at which to start the next search in `self.buf`.
302    search_pos: usize,
303    /// The absolute position of `search_pos` in the stream.
304    stream_pos: usize,
305    /// The position we report to the caller.
306    report_pos: usize,
307    /// The current seek position.
308    seek_pos: usize,
309    /// The length of the stream.
310    stream_len: usize,
311}
312
313impl<'n, 's, R: Read> FindIter<'n, 's, R> {
314    pub(crate) fn new(rdr: &'s mut R, fdr: &'n StreamFinder<'n>) -> Self {
315        let needle = fdr.needle();
316        let buf = Buffer::new(needle.len());
317        FindIter {
318            rdr,
319            needle,
320            buf,
321            search_pos: 0,
322            stream_pos: 0,
323            report_pos: 0,
324        }
325    }
326
327    pub(crate) fn new_with_needle(rdr: &'s mut R, needle: &'n [u8]) -> Self {
328        let buf = Buffer::new(needle.len());
329        FindIter {
330            rdr,
331            needle,
332            buf,
333            search_pos: 0,
334            stream_pos: 0,
335            report_pos: 0,
336        }
337    }
338}
339
340impl<'n, 's, R: Read + Seek> FindRevIter<'n, 's, R> {
341    pub(crate) fn new(
342        rdr: &'s mut R,
343        fdr: &'n StreamFinder<'n>,
344    ) -> io::Result<Self> {
345        let stream_len = rdr.seek(SeekFrom::End(0))?;
346        assert!(stream_len <= usize::MAX as u64);
347        let stream_len = stream_len as usize;
348
349        let needle = fdr.needle();
350        let buf = BufferRev::new(needle.len());
351        Ok(FindRevIter {
352            rdr,
353            needle,
354            buf,
355            search_pos: 0,
356            stream_pos: stream_len,
357            report_pos: 0,
358            seek_pos: stream_len,
359            stream_len,
360        })
361    }
362
363    pub(crate) fn new_with_needle(
364        rdr: &'s mut R,
365        needle: &'n [u8],
366    ) -> io::Result<Self> {
367        let stream_len = rdr.seek(SeekFrom::End(0))?;
368        assert!(stream_len <= usize::MAX as u64);
369        let stream_len = stream_len as usize;
370
371        let buf = BufferRev::new(needle.len());
372        Ok(FindRevIter {
373            rdr,
374            needle,
375            buf,
376            search_pos: 0,
377            stream_pos: stream_len,
378            report_pos: 0,
379            seek_pos: stream_len,
380            stream_len,
381        })
382    }
383
384    /// Returns the length of the underlying stream.
385    ///
386    /// # Examples
387    ///
388    /// ```
389    /// use std::io::{self, Read, Cursor};
390    ///
391    /// fn main() -> io::Result<()> {
392    ///     let mut stream = Cursor::new(b"hello rustaceans");
393    ///     let mut iter = xfind::rfind_iter(b"rust", &mut stream)?;
394    ///     assert_eq!(iter.stream_len(), 16);
395    ///
396    ///     Ok(())
397    /// }
398    /// ```
399    pub fn stream_len(&self) -> usize {
400        self.stream_len
401    }
402
403    /// Moves the cursor of the underlying stream to the given position.
404    ///
405    /// This is equivalent to call `rdr.seek(SeekFrom::Start(pos))`.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use std::io::{self, Read, Cursor};
411    ///
412    /// fn main() -> io::Result<()> {
413    ///     let mut stream = Cursor::new(b"hello rustaceans");
414    ///     let mut iter = xfind::rfind_iter(b"rust", &mut stream)?;
415    ///     let mut buf = Vec::new();
416    ///
417    ///     let pos = iter.next().unwrap()?;
418    ///     iter.seek_to(pos)?;
419    ///     stream.read_to_end(&mut buf)?;
420    ///     assert_eq!(buf, b"rustaceans");
421    ///
422    ///     Ok(())
423    /// }
424    /// ```
425    pub fn seek_to(&mut self, pos: usize) -> io::Result<()> {
426        self.rdr.seek(SeekFrom::Start(pos as u64)).map(|_| ())
427    }
428}
429
430impl<'n, 's, R: Read> Iterator for FindIter<'n, 's, R> {
431    type Item = io::Result<usize>;
432
433    fn next(&mut self) -> Option<Self::Item> {
434        loop {
435            if self.search_pos < self.buf.len() {
436                if let Some(mat) = memmem::find(
437                    &self.buf.buffer()[self.search_pos..],
438                    self.needle,
439                ) {
440                    self.report_pos = self.stream_pos + mat;
441                    self.stream_pos += mat + self.needle.len();
442                    self.search_pos += mat + self.needle.len();
443                    return Some(Ok(self.report_pos));
444                }
445
446                self.stream_pos += self.buf.len() - self.search_pos;
447                self.search_pos = self.buf.len();
448            }
449
450            // Roll our buffer if our buffer has at least the minimum amount of bytes in it.
451            if self.buf.len() >= self.buf.min_buffer_len() {
452                self.buf.roll();
453                if &self.buf.buffer()[..self.buf.min_buffer_len()]
454                    == self.needle
455                {
456                    self.search_pos = self.buf.min_buffer_len();
457                } else {
458                    self.stream_pos -= self.buf.min_buffer_len();
459                    self.search_pos = 0;
460                }
461            }
462            match self.buf.fill(&mut self.rdr) {
463                // report any I/O errors.
464                Err(err) => return Some(Err(err)),
465                // we've reach EOF, return `None` now.
466                Ok(false) => {
467                    return None;
468                }
469                // fallthrough for another search.
470                Ok(true) => {}
471            }
472        }
473    }
474}
475
476impl<'n, 's, R: Read + Seek> Iterator for FindRevIter<'n, 's, R> {
477    type Item = io::Result<usize>;
478
479    fn next(&mut self) -> Option<Self::Item> {
480        loop {
481            // If the contents of the buffer have not been consumed yet.
482            if self.search_pos < self.buf.len() {
483                if let Some(mat) = memmem::rfind(
484                    &self.buf.buffer()[..self.buf.len() - self.search_pos],
485                    self.needle,
486                ) {
487                    self.report_pos = self.stream_pos
488                        - (self.buf.len() - self.search_pos - mat);
489                    self.stream_pos -= self.buf.len() - self.search_pos - mat;
490                    self.search_pos += self.buf.len() - self.search_pos - mat;
491
492                    // FIXME: This is a quick and dirty hack to fix end-of-stream roll issues. We
493                    // should probably figure out a better way to handle this.
494                    if self.stream_len > self.buf.capacity()
495                        && self.seek_pos == 0
496                    {
497                        return Some(Ok(self.report_pos + self.needle.len()));
498                    }
499
500                    return Some(Ok(self.report_pos));
501                }
502
503                self.stream_pos = self
504                    .stream_pos
505                    .saturating_sub(self.buf.len() - self.search_pos);
506                self.search_pos = self.buf.len();
507            }
508
509            // We have nothing left to search if seek position is 0.
510            if self.seek_pos == 0 {
511                return None;
512            }
513
514            // Roll our buffer if our buffer has at least the minimum amount of bytes in it.
515            if self.buf.len() >= self.buf.min_buffer_len() {
516                self.buf.roll_right();
517
518                if &self.buf.buffer()
519                    [self.buf.len() - self.buf.min_buffer_len()..]
520                    == self.needle
521                {
522                    self.search_pos = self.buf.min_buffer_len();
523                } else {
524                    self.stream_pos += self.buf.min_buffer_len();
525                    self.search_pos = 0;
526                }
527            }
528
529            let free_buffer_len = self.buf.free_buffer().len();
530            let amount = if self.stream_pos > free_buffer_len {
531                self.seek_pos -= free_buffer_len;
532                free_buffer_len
533            } else {
534                self.seek_pos = 0;
535                self.stream_pos
536            };
537            match self.rdr.seek(SeekFrom::Start(self.seek_pos as u64)) {
538                Ok(_) => {}
539                Err(e) => return Some(Err(e)),
540            }
541            match self.buf.fill_exact(&mut self.rdr, amount) {
542                // report any I/O errors.
543                Err(err) => return Some(Err(err)),
544                // we've reach EOF, return `None` now.
545                Ok(false) => {
546                    return None;
547                }
548                // fallthrough for another search.
549                Ok(true) => {}
550            }
551        }
552    }
553}
554
555#[cfg(test)]
556mod tests {
557    use super::*;
558    use crate::buffer::DEFAULT_BUFFER_CAPACITY;
559    use std::io::Cursor;
560    use std::iter::repeat;
561
562    #[test]
563    fn test_find_iter_n1s1() {
564        let haystack = b"1";
565        let mut haystack = Cursor::new(haystack);
566
567        let finder = StreamFinder::new(b"1");
568        let matches: Vec<usize> =
569            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
570        let expected: Vec<usize> = vec![0];
571        assert_eq!(matches, expected);
572
573        let finder = StreamFinder::new(b"0");
574        let matches: Vec<usize> =
575            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
576        let expected: Vec<usize> = vec![];
577        assert_eq!(matches, expected);
578    }
579
580    #[test]
581    fn test_find_rev_iter_n1s1() {
582        let haystack = b"1";
583        let mut haystack = Cursor::new(haystack);
584
585        let finder = StreamFinder::new(b"1");
586        let matches: Vec<usize> = finder
587            .rfind_iter(&mut haystack)
588            .unwrap()
589            .map(|x| x.unwrap())
590            .collect();
591        let expected: Vec<usize> = vec![0];
592        assert_eq!(matches, expected);
593
594        let finder = StreamFinder::new(b"0");
595        let matches: Vec<usize> = finder
596            .rfind_iter(&mut haystack)
597            .unwrap()
598            .map(|x| x.unwrap())
599            .collect();
600        let expected: Vec<usize> = vec![];
601        assert_eq!(matches, expected);
602    }
603
604    #[test]
605    fn test_find_iter_n2s1() {
606        let haystack = b"1";
607        let mut haystack = Cursor::new(haystack);
608
609        let finder = StreamFinder::new(b"11");
610        let matches: Vec<usize> =
611            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
612        let expected: Vec<usize> = vec![];
613        assert_eq!(matches, expected);
614    }
615
616    #[test]
617    fn test_find_rev_iter_n2s1() {
618        let haystack = b"1";
619        let mut haystack = Cursor::new(haystack);
620
621        let finder = StreamFinder::new(b"11");
622        let matches: Vec<usize> = finder
623            .rfind_iter(&mut haystack)
624            .unwrap()
625            .map(|x| x.unwrap())
626            .collect();
627        let expected: Vec<usize> = vec![];
628        assert_eq!(matches, expected);
629    }
630
631    #[test]
632    fn test_find_iter_n1s21() {
633        let haystack = b"11 - 1 - 11  - 1 - 11";
634        let mut haystack = Cursor::new(haystack);
635
636        let finder = StreamFinder::new(b"1");
637        let matches: Vec<usize> =
638            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
639        let expected: Vec<usize> = vec![0, 1, 5, 9, 10, 15, 19, 20];
640        assert_eq!(matches, expected);
641    }
642
643    #[test]
644    fn test_find_rev_iter_n1s21() {
645        let haystack = b"11 - 1 - 11  - 1 - 11";
646        let mut haystack = Cursor::new(haystack);
647
648        let finder = StreamFinder::new(b"1");
649        let matches: Vec<usize> = finder
650            .rfind_iter(&mut haystack)
651            .unwrap()
652            .map(|x| x.unwrap())
653            .collect();
654        let expected: Vec<usize> =
655            vec![0, 1, 5, 9, 10, 15, 19, 20].into_iter().rev().collect();
656        assert_eq!(matches, expected);
657    }
658
659    #[test]
660    fn test_find_iter_n1s8213() {
661        let haystack: Vec<u8> = repeat(&0u8)
662            .take(DEFAULT_BUFFER_CAPACITY)
663            .chain("42 0 42 42 0 42".as_bytes())
664            .copied()
665            .collect();
666        let mut haystack = Cursor::new(haystack);
667
668        let finder = StreamFinder::new(b"4");
669        let matches: Vec<usize> =
670            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
671        let expected: Vec<usize> = vec![0, 5, 8, 13]
672            .into_iter()
673            .map(|x| x + DEFAULT_BUFFER_CAPACITY)
674            .collect();
675        assert_eq!(matches, expected);
676    }
677
678    #[test]
679    fn test_find_rev_iter_n1s8213() {
680        let haystack: Vec<u8> = repeat(&0u8)
681            .take(DEFAULT_BUFFER_CAPACITY)
682            .chain("42 0 42 42 0 42".as_bytes())
683            .copied()
684            .collect();
685        let mut haystack = Cursor::new(haystack);
686
687        let finder = StreamFinder::new(b"4");
688        let matches: Vec<usize> = finder
689            .rfind_iter(&mut haystack)
690            .unwrap()
691            .map(|x| x.unwrap())
692            .collect();
693        let expected: Vec<usize> = vec![0, 5, 8, 13]
694            .into_iter()
695            .map(|x| x + DEFAULT_BUFFER_CAPACITY)
696            .rev()
697            .collect();
698        assert_eq!(matches, expected);
699    }
700
701    #[test]
702    fn test_find_iter_n2s8213() {
703        let haystack: Vec<u8> = repeat(&0u8)
704            .take(DEFAULT_BUFFER_CAPACITY)
705            .chain("42 0 42 42 0 42".as_bytes())
706            .copied()
707            .collect();
708        let mut haystack = Cursor::new(haystack);
709
710        let finder = StreamFinder::new(b"42");
711        let matches: Vec<usize> =
712            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
713        let expected: Vec<usize> = vec![0, 5, 8, 13]
714            .into_iter()
715            .map(|x| x + DEFAULT_BUFFER_CAPACITY)
716            .collect();
717        assert_eq!(matches, expected);
718    }
719
720    #[test]
721    fn test_find_rev_iter_n2s8213() {
722        let haystack: Vec<u8> = repeat(&0u8)
723            .take(DEFAULT_BUFFER_CAPACITY)
724            .chain("42 0 42 42 0 42".as_bytes())
725            .copied()
726            .collect();
727        let mut haystack = Cursor::new(haystack);
728
729        let finder = StreamFinder::new(b"42");
730        let matches: Vec<usize> = finder
731            .rfind_iter(&mut haystack)
732            .unwrap()
733            .map(|x| x.unwrap())
734            .collect();
735        let expected: Vec<usize> = vec![0, 5, 8, 13]
736            .into_iter()
737            .map(|x| x + DEFAULT_BUFFER_CAPACITY)
738            .rev()
739            .collect();
740        assert_eq!(matches, expected);
741    }
742
743    #[test]
744    fn test_find_iter_n2s8212() {
745        let haystack: Vec<u8> = repeat(&0u8)
746            .take(DEFAULT_BUFFER_CAPACITY - 1)
747            .chain("42 0 42 42 0 42".as_bytes())
748            .copied()
749            .collect();
750        let mut haystack = Cursor::new(haystack);
751
752        let finder = StreamFinder::new(b"42");
753        let matches: Vec<usize> =
754            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
755        let expected: Vec<usize> = vec![0, 5, 8, 13]
756            .into_iter()
757            .map(|x| x + DEFAULT_BUFFER_CAPACITY - 1)
758            .collect();
759        assert_eq!(matches, expected);
760    }
761
762    #[test]
763    fn test_find_rev_iter_n2s8212() {
764        let haystack: Vec<u8> = repeat(&0u8)
765            .take(DEFAULT_BUFFER_CAPACITY - 1)
766            .chain("42 0 42 42 0 42".as_bytes())
767            .copied()
768            .collect();
769        let mut haystack = Cursor::new(haystack);
770
771        let finder = StreamFinder::new(b"42");
772        let matches: Vec<usize> = finder
773            .rfind_iter(&mut haystack)
774            .unwrap()
775            .map(|x| x.unwrap())
776            .collect();
777        let expected: Vec<usize> = vec![0, 5, 8, 13]
778            .into_iter()
779            .map(|x| x + DEFAULT_BUFFER_CAPACITY - 1)
780            .rev()
781            .collect();
782        assert_eq!(matches, expected);
783    }
784
785    #[test]
786    fn test_find_iter_n3s8212() {
787        let haystack: Vec<u8> = repeat(&0u8)
788            .take(DEFAULT_BUFFER_CAPACITY - 1)
789            .chain("42 0 42 42 0 42".as_bytes())
790            .copied()
791            .collect();
792        let mut haystack = Cursor::new(haystack);
793
794        let finder = StreamFinder::new(b"42 ");
795        let matches: Vec<usize> =
796            finder.find_iter(&mut haystack).map(|x| x.unwrap()).collect();
797        let expected: Vec<usize> = vec![0, 5, 8]
798            .into_iter()
799            .map(|x| x + DEFAULT_BUFFER_CAPACITY - 1)
800            .collect();
801        assert_eq!(matches, expected);
802    }
803
804    #[test]
805    fn test_find_rev_iter_n3s8212() {
806        let haystack: Vec<u8> = repeat(&0u8)
807            .take(DEFAULT_BUFFER_CAPACITY - 1)
808            .chain("42 0 42 42 0 42".as_bytes())
809            .copied()
810            .collect();
811        let mut haystack = Cursor::new(haystack);
812
813        let finder = StreamFinder::new(b"42 ");
814        let matches: Vec<usize> = finder
815            .rfind_iter(&mut haystack)
816            .unwrap()
817            .map(|x| x.unwrap())
818            .collect();
819        let expected: Vec<usize> = vec![0, 5, 8]
820            .into_iter()
821            .map(|x| x + DEFAULT_BUFFER_CAPACITY - 1)
822            .rev()
823            .collect();
824        assert_eq!(matches, expected);
825    }
826}