simple_string_patterns/
matches.rs1use crate::ci_engine;
2use alphanumeric::CharType;
3
4pub trait SimpleMatch {
8 fn equals_ci(&self, pattern: &str) -> bool;
10
11 fn equals_ci_alphanum(&self, pattern: &str) -> bool;
13
14 fn starts_with_ci(&self, pattern: &str) -> bool;
16
17 fn starts_with_ci_alphanum(&self, pattern: &str) -> bool;
19
20 fn ends_with_ci(&self, pattern: &str) -> bool;
22
23 fn ends_with_ci_alphanum(&self, pattern: &str) -> bool;
25
26 fn contains_ci(&self, pattern: &str) -> bool;
28
29 fn contains_ci_alphanum(&self, pattern: &str) -> bool;
31}
32
33impl<T: AsRef<str>> SimpleMatch for T {
34 fn equals_ci(&self, pattern: &str) -> bool {
35 ci_engine::ci_eq(self.as_ref(), pattern)
36 }
37
38 fn equals_ci_alphanum(&self, pattern: &str) -> bool {
39 ci_engine::ci_alphanum_eq(self.as_ref(), pattern)
40 }
41
42 fn starts_with_ci(&self, pattern: &str) -> bool {
43 ci_engine::ci_starts_with(self.as_ref(), pattern)
44 }
45
46 fn starts_with_ci_alphanum(&self, pattern: &str) -> bool {
47 ci_engine::ci_alphanum_starts_with(self.as_ref(), pattern)
48 }
49
50 fn ends_with_ci(&self, pattern: &str) -> bool {
51 ci_engine::ci_ends_with(self.as_ref(), pattern)
52 }
53
54 fn ends_with_ci_alphanum(&self, pattern: &str) -> bool {
55 ci_engine::ci_alphanum_ends_with(self.as_ref(), pattern)
56 }
57
58 fn contains_ci(&self, pattern: &str) -> bool {
59 ci_engine::ci_contains(self.as_ref(), pattern)
60 }
61
62 fn contains_ci_alphanum(&self, pattern: &str) -> bool {
63 ci_engine::ci_alphanum_contains(self.as_ref(), pattern)
64 }
65}
66
67pub trait MatchOccurrences {
69 fn find_matched_indices(&self, pat: &str) -> Vec<usize>;
72
73 fn find_char_indices(&self, pat: char) -> Vec<usize>;
75}
76
77impl<T: AsRef<str>> MatchOccurrences for T {
78 fn find_matched_indices(&self, pat: &str) -> Vec<usize> {
79 self.as_ref()
80 .match_indices(pat)
81 .into_iter()
82 .map(|pair| pair.0)
83 .collect::<Vec<usize>>()
84 }
85
86 fn find_char_indices(&self, pat: char) -> Vec<usize> {
87 self.as_ref()
88 .match_indices(pat)
89 .into_iter()
90 .map(|pair| pair.0)
91 .collect::<Vec<usize>>()
92 }
93}
94
95pub trait SimplContainsType
97where
98 Self: SimpleMatch,
99{
100 fn contains_type(&self, char_type: CharType) -> bool;
102
103 fn contains_types(&self, char_types: &[CharType]) -> bool;
105
106 fn starts_with_type(&self, char_type: CharType) -> bool;
108
109 fn starts_with_types(&self, char_types: &[CharType]) -> bool;
111
112 fn ends_with_type(&self, char_type: CharType) -> bool;
114
115 fn ends_with_types(&self, char_types: &[CharType]) -> bool;
117}
118
119impl<T: AsRef<str>> SimplContainsType for T {
120 fn contains_type(&self, char_type: CharType) -> bool {
121 self.as_ref().chars().any(|ch| char_type.is_in_range(&ch))
122 }
123
124 fn contains_types(&self, char_types: &[CharType]) -> bool {
125 self.as_ref()
126 .chars()
127 .any(|ch| char_types.into_iter().any(|ct| ct.is_in_range(&ch)))
128 }
129
130 fn starts_with_type(&self, char_type: CharType) -> bool {
131 if let Some(first) = self.as_ref().chars().nth(0) {
132 char_type.is_in_range(&first)
133 } else {
134 false
135 }
136 }
137
138 fn starts_with_types(&self, char_types: &[CharType]) -> bool {
139 if let Some(first) = self.as_ref().chars().nth(0) {
140 char_types.into_iter().any(|ct| ct.is_in_range(&first))
141 } else {
142 false
143 }
144 }
145
146 fn ends_with_type(&self, char_type: CharType) -> bool {
147 if let Some(first) = self.as_ref().chars().last() {
148 char_type.is_in_range(&first)
149 } else {
150 false
151 }
152 }
153
154 fn ends_with_types(&self, char_types: &[CharType]) -> bool {
155 if let Some(first) = self.as_ref().chars().last() {
156 char_types.into_iter().any(|ct| ct.is_in_range(&first))
157 } else {
158 false
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_equals_ci() {
169 assert!("Hello World".equals_ci("hello world"));
170 assert!("RUST".equals_ci("rust"));
171 assert!(!"Hello".equals_ci("World"));
172 assert!("".equals_ci(""));
173 }
174
175 #[test]
176 fn test_equals_ci_alphanum() {
177 assert!("Start-Up".equals_ci_alphanum("startup"));
178 assert!("hello---world".equals_ci_alphanum("HELLOWORLD"));
179 assert!(!"abc".equals_ci_alphanum("xyz"));
180 }
181
182 #[test]
183 fn test_starts_with_ci() {
184 assert!("Hello World".starts_with_ci("hello"));
185 assert!("Hello World".starts_with_ci("HELLO"));
186 assert!(!"Hello World".starts_with_ci("world"));
187 assert!("Hello".starts_with_ci(""));
188 }
189
190 #[test]
191 fn test_starts_with_ci_alphanum() {
192 assert!("_Cat-image".starts_with_ci_alphanum("cat"));
193 assert!("---Hello!!!".starts_with_ci_alphanum("hello"));
194 assert!(!"Dog-photo".starts_with_ci_alphanum("cat"));
195 }
196
197 #[test]
198 fn test_ends_with_ci() {
199 assert!("Hello World".ends_with_ci("WORLD"));
200 assert!("photo.JPG".ends_with_ci(".jpg"));
201 assert!(!"photo.png".ends_with_ci(".jpg"));
202 assert!("Hello".ends_with_ci(""));
203 }
204
205 #[test]
206 fn test_ends_with_ci_alphanum() {
207 assert!("photo-file.JPG!!!".ends_with_ci_alphanum("jpg"));
208 assert!("data---CSV".ends_with_ci_alphanum("csv"));
209 assert!(!"photo.png".ends_with_ci_alphanum("jpg"));
210 }
211
212 #[test]
213 fn test_contains_ci() {
214 assert!("Hello World".contains_ci("LO WO"));
215 assert!("ABCDEF".contains_ci("cde"));
216 assert!(!"Hello".contains_ci("xyz"));
217 assert!("Hello".contains_ci(""));
218 }
219
220 #[test]
221 fn test_contains_ci_alphanum() {
222 assert!("He--llo Wo!!rld".contains_ci_alphanum("lloworld"));
223 assert!("a-b-c-d".contains_ci_alphanum("ABCD"));
224 assert!(!"Hello".contains_ci_alphanum("xyz"));
225 }
226
227 #[test]
228 fn test_find_matched_indices() {
229 assert_eq!("abcabc".find_matched_indices("bc"), vec![1, 4]);
230 assert_eq!("hello".find_matched_indices("ll"), vec![2]);
231 assert_eq!("hello".find_matched_indices("xyz"), vec![]);
232 assert_eq!("aaa".find_matched_indices("a"), vec![0, 1, 2]);
233 }
234
235 #[test]
236 fn test_find_char_indices() {
237 assert_eq!("a.b.c".find_char_indices('.'), vec![1, 3]);
238 assert_eq!("hello".find_char_indices('l'), vec![2, 3]);
239 assert_eq!("hello".find_char_indices('z'), vec![]);
240 }
241
242 #[test]
243 fn test_contains_type() {
244 assert!("abc123".contains_type(CharType::DecDigit));
245 assert!(!"abcdef".contains_type(CharType::DecDigit));
246 assert!("Hello World".contains_type(CharType::Spaces));
247 assert!(!"HelloWorld".contains_type(CharType::Spaces));
248 assert!("hello!".contains_type(CharType::Punctuation));
249 }
250
251 #[test]
252 fn test_contains_types() {
253 assert!("abc".contains_types(&[CharType::DecDigit, CharType::Alpha]));
254 assert!(!"123".contains_types(&[CharType::Alpha, CharType::Spaces]));
255 assert!("hello world".contains_types(&[CharType::Spaces, CharType::Upper]));
256 }
257
258 #[test]
259 fn test_starts_with_type() {
260 assert!("123abc".starts_with_type(CharType::DecDigit));
261 assert!(!"abc123".starts_with_type(CharType::DecDigit));
262 assert!("Hello".starts_with_type(CharType::Upper));
263 assert!(!"hello".starts_with_type(CharType::Upper));
264 assert!(!("".starts_with_type(CharType::Alpha)));
265 }
266
267 #[test]
268 fn test_starts_with_types() {
269 assert!("Hello".starts_with_types(&[CharType::Upper, CharType::DecDigit]));
270 assert!("9lives".starts_with_types(&[CharType::Upper, CharType::DecDigit]));
271 assert!(!"hello".starts_with_types(&[CharType::Upper, CharType::DecDigit]));
272 assert!(!("".starts_with_types(&[CharType::Alpha])));
273 }
274
275 #[test]
276 fn test_ends_with_type() {
277 assert!("abc9".ends_with_type(CharType::DecDigit));
278 assert!(!"abc".ends_with_type(CharType::DecDigit));
279 assert!("hellO".ends_with_type(CharType::Upper));
280 assert!(!("".ends_with_type(CharType::Alpha)));
281 }
282
283 #[test]
284 fn test_ends_with_types() {
285 assert!("hello!".ends_with_types(&[CharType::Punctuation, CharType::DecDigit]));
286 assert!("test9".ends_with_types(&[CharType::Punctuation, CharType::DecDigit]));
287 assert!(!"hello".ends_with_types(&[CharType::Punctuation, CharType::DecDigit]));
288 assert!(!("".ends_with_types(&[CharType::Alpha])));
289 }
290}