1pub(crate) fn find_bytes(haystack: &[u8], needle: &[u8]) -> Option<usize> {
2 if needle.is_empty() {
3 return Some(0);
4 }
5
6 if needle.len() == 1 {
7 return memchr::memchr(needle[0], haystack);
8 }
9
10 memchr::memmem::find(haystack, needle)
11}
12
13pub(crate) fn rfind_bytes(haystack: &[u8], needle: &[u8]) -> Option<usize> {
14 if needle.is_empty() {
15 return Some(haystack.len());
16 }
17
18 if needle.len() == 1 {
19 return memchr::memrchr(needle[0], haystack);
20 }
21
22 memchr::memmem::rfind(haystack, needle)
23}
24
25pub struct CheetahFinder<'a> {
27 needle: &'a str,
28 finder: Option<memchr::memmem::Finder<'a>>,
29}
30
31impl<'a> CheetahFinder<'a> {
32 #[inline]
34 pub fn new(needle: &'a str) -> Self {
35 let finder = (needle.len() > 1).then(|| memchr::memmem::Finder::new(needle.as_bytes()));
36 Self { needle, finder }
37 }
38
39 #[inline]
41 pub fn needle(&self) -> &'a str {
42 self.needle
43 }
44
45 #[inline]
47 pub fn find_in<S>(&self, haystack: &S) -> Option<usize>
48 where
49 S: AsRef<str> + ?Sized,
50 {
51 let haystack = haystack.as_ref().as_bytes();
52
53 if self.needle.is_empty() {
54 return Some(0);
55 }
56
57 if self.needle.len() == 1 {
58 return memchr::memchr(self.needle.as_bytes()[0], haystack);
59 }
60
61 self.finder
62 .as_ref()
63 .and_then(|finder| finder.find(haystack))
64 }
65
66 #[inline]
68 pub fn is_match<S>(&self, haystack: &S) -> bool
69 where
70 S: AsRef<str> + ?Sized,
71 {
72 self.find_in(haystack).is_some()
73 }
74}