str_utils/
ends_with_ignore_ascii_case_multiple.rs

1/// To extend types which implement `AsRef<[u8]>` to have `ends_with_ignore_ascii_case_multiple`, `ends_with_ignore_ascii_case_with_lowercase_multiple` and `ends_with_ignore_ascii_case_with_uppercase_multiple` methods.
2pub trait EndsWithIgnoreAsciiCaseMultiple {
3    /// Returns `Some(usize)` if one of the given string slices case-insensitively (only ignoring ASCII case) matches a suffix of this string slice.
4    fn ends_with_ignore_ascii_case_multiple<S: AsRef<[u8]>>(&self, bs: &[S]) -> Option<usize>;
5
6    /// Returns `Some(usize)` if one of the given lowercase string slices case-insensitively (only ignoring ASCII case) matches a suffix of this string slice.
7    fn ends_with_ignore_ascii_case_with_lowercase_multiple<S: AsRef<[u8]>>(
8        &self,
9        bs: &[S],
10    ) -> Option<usize>;
11
12    /// Returns `Some(usize)` if one of the given uppercase string slices case-insensitively (only ignoring ASCII case) matches a suffix of this string slice.
13    fn ends_with_ignore_ascii_case_with_uppercase_multiple<S: AsRef<[u8]>>(
14        &self,
15        bs: &[S],
16    ) -> Option<usize>;
17}
18
19impl<T: AsRef<[u8]>> EndsWithIgnoreAsciiCaseMultiple for T {
20    #[inline]
21    fn ends_with_ignore_ascii_case_multiple<S: AsRef<[u8]>>(&self, bs: &[S]) -> Option<usize> {
22        let a = self.as_ref();
23        let a_length = a.len();
24
25        for (i, b) in bs.iter().enumerate() {
26            let b = b.as_ref();
27
28            let b_length = b.len();
29
30            if a_length < b_length {
31                continue;
32            }
33
34            if unsafe { a.get_unchecked((a_length - b_length)..) }.eq_ignore_ascii_case(b) {
35                return Some(i);
36            }
37        }
38
39        None
40    }
41
42    #[inline]
43    fn ends_with_ignore_ascii_case_with_lowercase_multiple<S: AsRef<[u8]>>(
44        &self,
45        bs: &[S],
46    ) -> Option<usize> {
47        let a = self.as_ref();
48        let a_length = a.len();
49
50        for (i, b) in bs.iter().enumerate() {
51            let b = b.as_ref();
52
53            debug_assert!(!b.iter().any(|e| e.is_ascii_uppercase()));
54
55            let b_length = b.len();
56
57            if a_length < b_length {
58                continue;
59            }
60
61            if !unsafe { a.get_unchecked((a_length - b_length)..) }
62                .iter()
63                .map(|e| e.to_ascii_lowercase())
64                .zip(b.iter().copied())
65                .any(|(ac, bc)| ac != bc)
66            {
67                return Some(i);
68            }
69        }
70
71        None
72    }
73
74    #[inline]
75    fn ends_with_ignore_ascii_case_with_uppercase_multiple<S: AsRef<[u8]>>(
76        &self,
77        bs: &[S],
78    ) -> Option<usize> {
79        let a = self.as_ref();
80        let a_length = a.len();
81
82        for (i, b) in bs.iter().enumerate() {
83            let b = b.as_ref();
84
85            debug_assert!(!b.iter().any(|e| e.is_ascii_lowercase()));
86
87            let b_length = b.len();
88
89            if a_length < b_length {
90                continue;
91            }
92
93            if !unsafe { a.get_unchecked((a_length - b_length)..) }
94                .iter()
95                .map(|e| e.to_ascii_uppercase())
96                .zip(b.iter().copied())
97                .any(|(ac, bc)| ac != bc)
98            {
99                return Some(i);
100            }
101        }
102
103        None
104    }
105}