memchr/memmem/mod.rs
1/*!
2This module provides forward and reverse substring search routines.
3
4Unlike the standard library's substring search routines, these work on
5arbitrary bytes. For all non-empty needles, these routines will report exactly
6the same values as the corresponding routines in the standard library. For
7the empty needle, the standard library reports matches only at valid UTF-8
8boundaries, where as these routines will report matches at every position.
9
10Other than being able to work on arbitrary bytes, the primary reason to prefer
11these routines over the standard library routines is that these will generally
12be faster. In some cases, significantly so.
13
14# Example: iterating over substring matches
15
16This example shows how to use [`find_iter`] to find occurrences of a substring
17in a haystack.
18
19```
20use memchr::memmem;
21
22let haystack = b"foo bar foo baz foo";
23
24let mut it = memmem::find_iter(haystack, "foo");
25assert_eq!(Some(0), it.next());
26assert_eq!(Some(8), it.next());
27assert_eq!(Some(16), it.next());
28assert_eq!(None, it.next());
29```
30
31# Example: iterating over substring matches in reverse
32
33This example shows how to use [`rfind_iter`] to find occurrences of a substring
34in a haystack starting from the end of the haystack.
35
36**NOTE:** This module does not implement double ended iterators, so reverse
37searches aren't done by calling `rev` on a forward iterator.
38
39```
40use memchr::memmem;
41
42let haystack = b"foo bar foo baz foo";
43
44let mut it = memmem::rfind_iter(haystack, "foo");
45assert_eq!(Some(16), it.next());
46assert_eq!(Some(8), it.next());
47assert_eq!(Some(0), it.next());
48assert_eq!(None, it.next());
49```
50
51# Example: repeating a search for the same needle
52
53It may be possible for the overhead of constructing a substring searcher to be
54measurable in some workloads. In cases where the same needle is used to search
55many haystacks, it is possible to do construction once and thus to avoid it for
56subsequent searches. This can be done with a [`Finder`] (or a [`FinderRev`] for
57reverse searches).
58
59```
60use memchr::memmem;
61
62let finder = memmem::Finder::new("foo");
63
64assert_eq!(Some(4), finder.find(b"baz foo quux"));
65assert_eq!(None, finder.find(b"quux baz bar"));
66```
67*/
68
69pub use crate::memmem::searcher::PrefilterConfig as Prefilter;
70
71// This is exported here for use in the crate::arch::all::twoway
72// implementation. This is essentially an abstraction breaker. Namely, the
73// public API of twoway doesn't support providing a prefilter, but its crate
74// internal API does. The main reason for this is that I didn't want to do the
75// API design required to support it without a concrete use case.
76pub(crate) use crate::memmem::searcher::Pre;
77
78use crate::{
79 arch::all::{
80 packedpair::{DefaultFrequencyRank, HeuristicFrequencyRank},
81 rabinkarp,
82 },
83 cow::CowBytes,
84 memmem::searcher::{PrefilterState, Searcher, SearcherRev},
85};
86
87mod searcher;
88
89/// Returns an iterator over all non-overlapping occurrences of a substring in
90/// a haystack.
91///
92/// # Complexity
93///
94/// This routine is guaranteed to have worst case linear time complexity
95/// with respect to both the needle and the haystack. That is, this runs
96/// in `O(needle.len() + haystack.len())` time.
97///
98/// This routine is also guaranteed to have worst case constant space
99/// complexity.
100///
101/// # Examples
102///
103/// Basic usage:
104///
105/// ```
106/// use memchr::memmem;
107///
108/// let haystack = b"foo bar foo baz foo";
109/// let mut it = memmem::find_iter(haystack, b"foo");
110/// assert_eq!(Some(0), it.next());
111/// assert_eq!(Some(8), it.next());
112/// assert_eq!(Some(16), it.next());
113/// assert_eq!(None, it.next());
114/// ```
115#[inline]
116pub fn find_iter<'h, 'n, N: 'n + ?Sized + AsRef<[u8]>>(
117 haystack: &'h [u8],
118 needle: &'n N,
119) -> FindIter<'h, 'n> {
120 FindIter::new(haystack, Finder::new(needle))
121}
122
123/// Returns a reverse iterator over all non-overlapping occurrences of a
124/// substring in a haystack.
125///
126/// # Complexity
127///
128/// This routine is guaranteed to have worst case linear time complexity
129/// with respect to both the needle and the haystack. That is, this runs
130/// in `O(needle.len() + haystack.len())` time.
131///
132/// This routine is also guaranteed to have worst case constant space
133/// complexity.
134///
135/// # Examples
136///
137/// Basic usage:
138///
139/// ```
140/// use memchr::memmem;
141///
142/// let haystack = b"foo bar foo baz foo";
143/// let mut it = memmem::rfind_iter(haystack, b"foo");
144/// assert_eq!(Some(16), it.next());
145/// assert_eq!(Some(8), it.next());
146/// assert_eq!(Some(0), it.next());
147/// assert_eq!(None, it.next());
148/// ```
149#[inline]
150pub fn rfind_iter<'h, 'n, N: 'n + ?Sized + AsRef<[u8]>>(
151 haystack: &'h [u8],
152 needle: &'n N,
153) -> FindRevIter<'h, 'n> {
154 FindRevIter::new(haystack, FinderRev::new(needle))
155}
156
157/// Returns the index of the first occurrence of the given needle.
158///
159/// Note that if you're are searching for the same needle in many different
160/// small haystacks, it may be faster to initialize a [`Finder`] once,
161/// and reuse it for each search.
162///
163/// # Complexity
164///
165/// This routine is guaranteed to have worst case linear time complexity
166/// with respect to both the needle and the haystack. That is, this runs
167/// in `O(needle.len() + haystack.len())` time.
168///
169/// This routine is also guaranteed to have worst case constant space
170/// complexity.
171///
172/// # Examples
173///
174/// Basic usage:
175///
176/// ```
177/// use memchr::memmem;
178///
179/// let haystack = b"foo bar baz";
180/// assert_eq!(Some(0), memmem::find(haystack, b"foo"));
181/// assert_eq!(Some(4), memmem::find(haystack, b"bar"));
182/// assert_eq!(None, memmem::find(haystack, b"quux"));
183/// ```
184#[inline]
185pub fn find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
186 if haystack.len() < 64 {
187 rabinkarp::Finder::new(needle).find(haystack, needle)
188 } else {
189 Finder::new(needle).find(haystack)
190 }
191}
192
193/// Returns the index of the last occurrence of the given needle.
194///
195/// Note that if you're are searching for the same needle in many different
196/// small haystacks, it may be faster to initialize a [`FinderRev`] once,
197/// and reuse it for each search.
198///
199/// # Complexity
200///
201/// This routine is guaranteed to have worst case linear time complexity
202/// with respect to both the needle and the haystack. That is, this runs
203/// in `O(needle.len() + haystack.len())` time.
204///
205/// This routine is also guaranteed to have worst case constant space
206/// complexity.
207///
208/// # Examples
209///
210/// Basic usage:
211///
212/// ```
213/// use memchr::memmem;
214///
215/// let haystack = b"foo bar baz";
216/// assert_eq!(Some(0), memmem::rfind(haystack, b"foo"));
217/// assert_eq!(Some(4), memmem::rfind(haystack, b"bar"));
218/// assert_eq!(Some(8), memmem::rfind(haystack, b"ba"));
219/// assert_eq!(None, memmem::rfind(haystack, b"quux"));
220/// ```
221#[inline]
222pub fn rfind(haystack: &[u8], needle: &[u8]) -> Option<usize> {
223 if haystack.len() < 64 {
224 rabinkarp::FinderRev::new(needle).rfind(haystack, needle)
225 } else {
226 FinderRev::new(needle).rfind(haystack)
227 }
228}
229
230/// An iterator over non-overlapping substring matches.
231///
232/// Matches are reported by the byte offset at which they begin.
233///
234/// `'h` is the lifetime of the haystack while `'n` is the lifetime of the
235/// needle.
236#[derive(Debug, Clone)]
237pub struct FindIter<'h, 'n> {
238 haystack: &'h [u8],
239 prestate: PrefilterState,
240 finder: Finder<'n>,
241 pos: usize,
242}
243
244impl<'h, 'n> FindIter<'h, 'n> {
245 #[inline(always)]
246 pub(crate) fn new(
247 haystack: &'h [u8],
248 finder: Finder<'n>,
249 ) -> FindIter<'h, 'n> {
250 let prestate = PrefilterState::new();
251 FindIter { haystack, prestate, finder, pos: 0 }
252 }
253
254 /// Convert this iterator into its owned variant, such that it no longer
255 /// borrows the finder and needle.
256 ///
257 /// If this is already an owned iterator, then this is a no-op. Otherwise,
258 /// this copies the needle.
259 ///
260 /// This is only available when the `alloc` feature is enabled.
261 #[cfg(feature = "alloc")]
262 #[inline]
263 pub fn into_owned(self) -> FindIter<'h, 'static> {
264 FindIter {
265 haystack: self.haystack,
266 prestate: self.prestate,
267 finder: self.finder.into_owned(),
268 pos: self.pos,
269 }
270 }
271}
272
273impl<'h, 'n> Iterator for FindIter<'h, 'n> {
274 type Item = usize;
275
276 fn next(&mut self) -> Option<usize> {
277 let needle = self.finder.needle();
278 let haystack = self.haystack.get(self.pos..)?;
279 let idx =
280 self.finder.searcher.find(&mut self.prestate, haystack, needle)?;
281
282 let pos = self.pos + idx;
283 self.pos = pos + needle.len().max(1);
284
285 Some(pos)
286 }
287
288 fn size_hint(&self) -> (usize, Option<usize>) {
289 // The largest possible number of non-overlapping matches is the
290 // quotient of the haystack and the needle (or the length of the
291 // haystack, if the needle is empty)
292 match self.haystack.len().checked_sub(self.pos) {
293 None => (0, Some(0)),
294 Some(haystack_len) => match self.finder.needle().len() {
295 // Empty needles always succeed and match at every point
296 // (including the very end)
297 0 => (
298 haystack_len.saturating_add(1),
299 haystack_len.checked_add(1),
300 ),
301 needle_len => (0, Some(haystack_len / needle_len)),
302 },
303 }
304 }
305}
306
307/// An iterator over non-overlapping substring matches in reverse.
308///
309/// Matches are reported by the byte offset at which they begin.
310///
311/// `'h` is the lifetime of the haystack while `'n` is the lifetime of the
312/// needle.
313#[derive(Clone, Debug)]
314pub struct FindRevIter<'h, 'n> {
315 haystack: &'h [u8],
316 finder: FinderRev<'n>,
317 /// When searching with an empty needle, this gets set to `None` after
318 /// we've yielded the last element at `0`.
319 pos: Option<usize>,
320}
321
322impl<'h, 'n> FindRevIter<'h, 'n> {
323 #[inline(always)]
324 pub(crate) fn new(
325 haystack: &'h [u8],
326 finder: FinderRev<'n>,
327 ) -> FindRevIter<'h, 'n> {
328 let pos = Some(haystack.len());
329 FindRevIter { haystack, finder, pos }
330 }
331
332 /// Convert this iterator into its owned variant, such that it no longer
333 /// borrows the finder and needle.
334 ///
335 /// If this is already an owned iterator, then this is a no-op. Otherwise,
336 /// this copies the needle.
337 ///
338 /// This is only available when the `std` feature is enabled.
339 #[cfg(feature = "alloc")]
340 #[inline]
341 pub fn into_owned(self) -> FindRevIter<'h, 'static> {
342 FindRevIter {
343 haystack: self.haystack,
344 finder: self.finder.into_owned(),
345 pos: self.pos,
346 }
347 }
348}
349
350impl<'h, 'n> Iterator for FindRevIter<'h, 'n> {
351 type Item = usize;
352
353 fn next(&mut self) -> Option<usize> {
354 let pos = self.pos?;
355 let result = self.finder.rfind(&self.haystack[..pos]);
356 match result {
357 None => None,
358 Some(i) => {
359 if pos == i {
360 self.pos = pos.checked_sub(1);
361 } else {
362 self.pos = Some(i);
363 }
364 Some(i)
365 }
366 }
367 }
368}
369
370/// A single substring searcher fixed to a particular needle.
371///
372/// The purpose of this type is to permit callers to construct a substring
373/// searcher that can be used to search haystacks without the overhead of
374/// constructing the searcher in the first place. This is a somewhat niche
375/// concern when it's necessary to re-use the same needle to search multiple
376/// different haystacks with as little overhead as possible. In general, using
377/// [`find`] is good enough, but `Finder` is useful when you can meaningfully
378/// observe searcher construction time in a profile.
379///
380/// When the `std` feature is enabled, then this type has an `into_owned`
381/// version which permits building a `Finder` that is not connected to
382/// the lifetime of its needle.
383#[derive(Clone, Debug)]
384pub struct Finder<'n> {
385 needle: CowBytes<'n>,
386 searcher: Searcher,
387}
388
389impl<'n> Finder<'n> {
390 /// Create a new finder for the given needle.
391 #[inline]
392 pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'n B) -> Finder<'n> {
393 FinderBuilder::new().build_forward(needle)
394 }
395
396 /// Returns the index of the first occurrence of this needle in the given
397 /// haystack.
398 ///
399 /// # Complexity
400 ///
401 /// This routine is guaranteed to have worst case linear time complexity
402 /// with respect to both the needle and the haystack. That is, this runs
403 /// in `O(needle.len() + haystack.len())` time.
404 ///
405 /// This routine is also guaranteed to have worst case constant space
406 /// complexity.
407 ///
408 /// # Examples
409 ///
410 /// Basic usage:
411 ///
412 /// ```
413 /// use memchr::memmem::Finder;
414 ///
415 /// let haystack = b"foo bar baz";
416 /// assert_eq!(Some(0), Finder::new("foo").find(haystack));
417 /// assert_eq!(Some(4), Finder::new("bar").find(haystack));
418 /// assert_eq!(None, Finder::new("quux").find(haystack));
419 /// ```
420 #[inline]
421 pub fn find(&self, haystack: &[u8]) -> Option<usize> {
422 let mut prestate = PrefilterState::new();
423 let needle = self.needle.as_slice();
424 self.searcher.find(&mut prestate, haystack, needle)
425 }
426
427 /// Returns an iterator over all occurrences of a substring in a haystack.
428 ///
429 /// # Complexity
430 ///
431 /// This routine is guaranteed to have worst case linear time complexity
432 /// with respect to both the needle and the haystack. That is, this runs
433 /// in `O(needle.len() + haystack.len())` time.
434 ///
435 /// This routine is also guaranteed to have worst case constant space
436 /// complexity.
437 ///
438 /// # Examples
439 ///
440 /// Basic usage:
441 ///
442 /// ```
443 /// use memchr::memmem::Finder;
444 ///
445 /// let haystack = b"foo bar foo baz foo";
446 /// let finder = Finder::new(b"foo");
447 /// let mut it = finder.find_iter(haystack);
448 /// assert_eq!(Some(0), it.next());
449 /// assert_eq!(Some(8), it.next());
450 /// assert_eq!(Some(16), it.next());
451 /// assert_eq!(None, it.next());
452 /// ```
453 #[inline]
454 pub fn find_iter<'a, 'h>(
455 &'a self,
456 haystack: &'h [u8],
457 ) -> FindIter<'h, 'a> {
458 FindIter::new(haystack, self.as_ref())
459 }
460
461 /// Convert this finder into its owned variant, such that it no longer
462 /// borrows the needle.
463 ///
464 /// If this is already an owned finder, then this is a no-op. Otherwise,
465 /// this copies the needle.
466 ///
467 /// This is only available when the `alloc` feature is enabled.
468 #[cfg(feature = "alloc")]
469 #[inline]
470 pub fn into_owned(self) -> Finder<'static> {
471 Finder { needle: self.needle.into_owned(), searcher: self.searcher }
472 }
473
474 /// Convert this finder into its borrowed variant.
475 ///
476 /// This is primarily useful if your finder is owned and you'd like to
477 /// store its borrowed variant in some intermediate data structure.
478 ///
479 /// Note that the lifetime parameter of the returned finder is tied to the
480 /// lifetime of `self`, and may be shorter than the `'n` lifetime of the
481 /// needle itself. Namely, a finder's needle can be either borrowed or
482 /// owned, so the lifetime of the needle returned must necessarily be the
483 /// shorter of the two.
484 #[inline]
485 pub fn as_ref(&self) -> Finder<'_> {
486 Finder {
487 needle: CowBytes::new(self.needle()),
488 searcher: self.searcher.clone(),
489 }
490 }
491
492 /// Returns the needle that this finder searches for.
493 ///
494 /// Note that the lifetime of the needle returned is tied to the lifetime
495 /// of the finder, and may be shorter than the `'n` lifetime. Namely, a
496 /// finder's needle can be either borrowed or owned, so the lifetime of the
497 /// needle returned must necessarily be the shorter of the two.
498 #[inline]
499 pub fn needle(&self) -> &[u8] {
500 self.needle.as_slice()
501 }
502}
503
504/// A single substring reverse searcher fixed to a particular needle.
505///
506/// The purpose of this type is to permit callers to construct a substring
507/// searcher that can be used to search haystacks without the overhead of
508/// constructing the searcher in the first place. This is a somewhat niche
509/// concern when it's necessary to re-use the same needle to search multiple
510/// different haystacks with as little overhead as possible. In general,
511/// using [`rfind`] is good enough, but `FinderRev` is useful when you can
512/// meaningfully observe searcher construction time in a profile.
513///
514/// When the `std` feature is enabled, then this type has an `into_owned`
515/// version which permits building a `FinderRev` that is not connected to
516/// the lifetime of its needle.
517#[derive(Clone, Debug)]
518pub struct FinderRev<'n> {
519 needle: CowBytes<'n>,
520 searcher: SearcherRev,
521}
522
523impl<'n> FinderRev<'n> {
524 /// Create a new reverse finder for the given needle.
525 #[inline]
526 pub fn new<B: ?Sized + AsRef<[u8]>>(needle: &'n B) -> FinderRev<'n> {
527 FinderBuilder::new().build_reverse(needle)
528 }
529
530 /// Returns the index of the last occurrence of this needle in the given
531 /// haystack.
532 ///
533 /// The haystack may be any type that can be cheaply converted into a
534 /// `&[u8]`. This includes, but is not limited to, `&str` and `&[u8]`.
535 ///
536 /// # Complexity
537 ///
538 /// This routine is guaranteed to have worst case linear time complexity
539 /// with respect to both the needle and the haystack. That is, this runs
540 /// in `O(needle.len() + haystack.len())` time.
541 ///
542 /// This routine is also guaranteed to have worst case constant space
543 /// complexity.
544 ///
545 /// # Examples
546 ///
547 /// Basic usage:
548 ///
549 /// ```
550 /// use memchr::memmem::FinderRev;
551 ///
552 /// let haystack = b"foo bar baz";
553 /// assert_eq!(Some(0), FinderRev::new("foo").rfind(haystack));
554 /// assert_eq!(Some(4), FinderRev::new("bar").rfind(haystack));
555 /// assert_eq!(None, FinderRev::new("quux").rfind(haystack));
556 /// ```
557 pub fn rfind<B: AsRef<[u8]>>(&self, haystack: B) -> Option<usize> {
558 self.searcher.rfind(haystack.as_ref(), self.needle.as_slice())
559 }
560
561 /// Returns a reverse iterator over all occurrences of a substring in a
562 /// haystack.
563 ///
564 /// # Complexity
565 ///
566 /// This routine is guaranteed to have worst case linear time complexity
567 /// with respect to both the needle and the haystack. That is, this runs
568 /// in `O(needle.len() + haystack.len())` time.
569 ///
570 /// This routine is also guaranteed to have worst case constant space
571 /// complexity.
572 ///
573 /// # Examples
574 ///
575 /// Basic usage:
576 ///
577 /// ```
578 /// use memchr::memmem::FinderRev;
579 ///
580 /// let haystack = b"foo bar foo baz foo";
581 /// let finder = FinderRev::new(b"foo");
582 /// let mut it = finder.rfind_iter(haystack);
583 /// assert_eq!(Some(16), it.next());
584 /// assert_eq!(Some(8), it.next());
585 /// assert_eq!(Some(0), it.next());
586 /// assert_eq!(None, it.next());
587 /// ```
588 #[inline]
589 pub fn rfind_iter<'a, 'h>(
590 &'a self,
591 haystack: &'h [u8],
592 ) -> FindRevIter<'h, 'a> {
593 FindRevIter::new(haystack, self.as_ref())
594 }
595
596 /// Convert this finder into its owned variant, such that it no longer
597 /// borrows the needle.
598 ///
599 /// If this is already an owned finder, then this is a no-op. Otherwise,
600 /// this copies the needle.
601 ///
602 /// This is only available when the `std` feature is enabled.
603 #[cfg(feature = "alloc")]
604 #[inline]
605 pub fn into_owned(self) -> FinderRev<'static> {
606 FinderRev { needle: self.needle.into_owned(), searcher: self.searcher }
607 }
608
609 /// Convert this finder into its borrowed variant.
610 ///
611 /// This is primarily useful if your finder is owned and you'd like to
612 /// store its borrowed variant in some intermediate data structure.
613 ///
614 /// Note that the lifetime parameter of the returned finder is tied to the
615 /// lifetime of `self`, and may be shorter than the `'n` lifetime of the
616 /// needle itself. Namely, a finder's needle can be either borrowed or
617 /// owned, so the lifetime of the needle returned must necessarily be the
618 /// shorter of the two.
619 #[inline]
620 pub fn as_ref(&self) -> FinderRev<'_> {
621 FinderRev {
622 needle: CowBytes::new(self.needle()),
623 searcher: self.searcher.clone(),
624 }
625 }
626
627 /// Returns the needle that this finder searches for.
628 ///
629 /// Note that the lifetime of the needle returned is tied to the lifetime
630 /// of the finder, and may be shorter than the `'n` lifetime. Namely, a
631 /// finder's needle can be either borrowed or owned, so the lifetime of the
632 /// needle returned must necessarily be the shorter of the two.
633 #[inline]
634 pub fn needle(&self) -> &[u8] {
635 self.needle.as_slice()
636 }
637}
638
639/// A builder for constructing non-default forward or reverse memmem finders.
640///
641/// A builder is primarily useful for configuring a substring searcher.
642/// Currently, the only configuration exposed is the ability to disable
643/// heuristic prefilters used to speed up certain searches.
644#[derive(Clone, Debug, Default)]
645pub struct FinderBuilder {
646 prefilter: Prefilter,
647}
648
649impl FinderBuilder {
650 /// Create a new finder builder with default settings.
651 pub fn new() -> FinderBuilder {
652 FinderBuilder::default()
653 }
654
655 /// Build a forward finder using the given needle from the current
656 /// settings.
657 pub fn build_forward<'n, B: ?Sized + AsRef<[u8]>>(
658 &self,
659 needle: &'n B,
660 ) -> Finder<'n> {
661 self.build_forward_with_ranker(DefaultFrequencyRank, needle)
662 }
663
664 /// Build an owned forward finder using the given needle from the current
665 /// settings.
666 #[cfg(feature = "alloc")]
667 pub fn build_forward_owned<B: Into<alloc::boxed::Box<[u8]>>>(
668 &self,
669 needle: B,
670 ) -> Finder<'static> {
671 self.build_forward_with_ranker_owned(DefaultFrequencyRank, needle)
672 }
673
674 /// Build a forward finder using the given needle and a custom heuristic
675 /// for determining the frequency of a given byte in the dataset. See
676 /// [`HeuristicFrequencyRank`] for more details.
677 pub fn build_forward_with_ranker<
678 'n,
679 R: HeuristicFrequencyRank,
680 B: ?Sized + AsRef<[u8]>,
681 >(
682 &self,
683 ranker: R,
684 needle: &'n B,
685 ) -> Finder<'n> {
686 let needle = needle.as_ref();
687 Finder {
688 needle: CowBytes::new(needle),
689 searcher: Searcher::new(self.prefilter, ranker, needle),
690 }
691 }
692
693 /// Build an owned forward finder using the given needle and a custom
694 /// heuristic for determining the frequency of a given byte in the dataset.
695 /// See [`HeuristicFrequencyRank`] for more details.
696 #[cfg(feature = "alloc")]
697 pub fn build_forward_with_ranker_owned<
698 R: HeuristicFrequencyRank,
699 B: Into<alloc::boxed::Box<[u8]>>,
700 >(
701 &self,
702 ranker: R,
703 needle: B,
704 ) -> Finder<'static> {
705 let needle = needle.into();
706 let searcher = Searcher::new(self.prefilter, ranker, &needle);
707 Finder { needle: CowBytes::new_owned(needle), searcher }
708 }
709
710 /// Build a reverse finder using the given needle from the current
711 /// settings.
712 pub fn build_reverse<'n, B: ?Sized + AsRef<[u8]>>(
713 &self,
714 needle: &'n B,
715 ) -> FinderRev<'n> {
716 let needle = needle.as_ref();
717 FinderRev {
718 needle: CowBytes::new(needle),
719 searcher: SearcherRev::new(needle),
720 }
721 }
722
723 /// Build an owned reverse finder using the given needle from the current
724 /// settings.
725 #[cfg(feature = "alloc")]
726 pub fn build_reverse_owned<B: Into<alloc::boxed::Box<[u8]>>>(
727 &self,
728 needle: B,
729 ) -> FinderRev<'static> {
730 let needle = needle.into();
731 let searcher = SearcherRev::new(&needle);
732 FinderRev { needle: CowBytes::new_owned(needle), searcher }
733 }
734
735 /// Configure the prefilter setting for the finder.
736 ///
737 /// See the documentation for [`Prefilter`] for more discussion on why
738 /// you might want to configure this.
739 pub fn prefilter(&mut self, prefilter: Prefilter) -> &mut FinderBuilder {
740 self.prefilter = prefilter;
741 self
742 }
743}
744
745#[cfg(test)]
746mod tests {
747 use super::*;
748
749 define_substring_forward_quickcheck!(|h, n| Some(Finder::new(n).find(h)));
750 define_substring_reverse_quickcheck!(|h, n| Some(
751 FinderRev::new(n).rfind(h)
752 ));
753
754 #[test]
755 fn forward() {
756 crate::tests::substring::Runner::new()
757 .fwd(|h, n| Some(Finder::new(n).find(h)))
758 .run();
759 }
760
761 #[test]
762 fn reverse() {
763 crate::tests::substring::Runner::new()
764 .rev(|h, n| Some(FinderRev::new(n).rfind(h)))
765 .run();
766 }
767}