-
Notifications
You must be signed in to change notification settings - Fork 1
/
lib.rs
97 lines (83 loc) · 2.55 KB
/
lib.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use std::iter::zip;
#[inline]
pub fn contains(haystack: &str, needle: &str) -> bool {
contains_kernel(haystack, needle, equals)
}
#[inline]
pub fn icontains(haystack: &str, needle: &str) -> bool {
debug_assert!(needle.is_ascii(), "needle must be ascii");
contains_kernel(haystack, needle, i_equals)
}
#[inline]
pub fn starts_with(haystack: &str, needle: &str) -> bool {
if needle.len() > haystack.len() {
false
} else {
zip(haystack.as_bytes(), needle.as_bytes()).all(equals)
}
}
#[inline]
pub fn istarts_with(haystack: &str, needle: &str) -> bool {
debug_assert!(needle.is_ascii(), "needle must be ascii");
if needle.len() > haystack.len() {
false
} else {
zip(haystack.as_bytes().iter(), needle.as_bytes().iter()).all(i_equals)
}
}
#[inline]
pub fn ends_with(haystack: &str, needle: &str) -> bool {
if needle.len() > haystack.len() {
false
} else {
zip(haystack.as_bytes().iter().rev(), needle.as_bytes().iter().rev()).all(equals)
}
}
#[inline]
pub fn iends_with(haystack: &str, needle: &str) -> bool {
debug_assert!(needle.is_ascii(), "needle must be ascii");
if needle.len() > haystack.len() {
false
} else {
zip(haystack.as_bytes().iter().rev(), needle.as_bytes().iter().rev()).all(i_equals)
}
}
fn i_equals((n, h): (&u8, &u8)) -> bool {
n.to_ascii_lowercase() == h.to_ascii_lowercase()
}
fn equals((n, h): (&u8, &u8)) -> bool {
n == h
}
fn contains_kernel(haystack: &str, needle: &str, kernel: impl Fn((&u8, &u8)) -> bool) -> bool {
let Some((needle_first, needle_rest)) = needle.as_bytes().split_first() else {
// needle is empty, contains always true, matches `str.contains()` behaviour
return true;
};
let mut hay_iter = haystack.as_bytes().iter();
if needle_rest.is_empty() {
return hay_iter.any(|h| kernel((needle_first, h)));
}
let Some(stop_at) = haystack.len().checked_sub(needle.len()) else {
// needle is longer than haystack
return false;
};
let mut index: usize = 0;
while let Some(hay_byte) = hay_iter.next() {
if kernel((needle_first, hay_byte)) && rest_match(needle_rest, hay_iter.clone(), &kernel) {
return true;
} else {
if index >= stop_at {
break;
}
index += 1;
}
}
false
}
fn rest_match<'a>(
needle_rest: &[u8],
hay_iter: impl Iterator<Item = &'a u8>,
kernel: impl Fn((&u8, &u8)) -> bool,
) -> bool {
zip(needle_rest, hay_iter).all(kernel)
}