1use crate::{JavaCodePoint, JavaStr};
2
3mod private_pattern {
4 use crate::{JavaCodePoint, JavaStr};
5
6 pub trait Sealed {}
7
8 impl Sealed for char {}
9 impl Sealed for JavaCodePoint {}
10 impl Sealed for &str {}
11 impl Sealed for &JavaStr {}
12 impl<F> Sealed for F where F: FnMut(JavaCodePoint) -> bool {}
13 impl Sealed for &[char] {}
14 impl Sealed for &[JavaCodePoint] {}
15 impl Sealed for &char {}
16 impl Sealed for &JavaCodePoint {}
17 impl Sealed for &&str {}
18 impl Sealed for &&JavaStr {}
19}
20
21pub unsafe trait JavaStrPattern: private_pattern::Sealed {
25 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize>;
26 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize>;
27 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)>;
28 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)>;
29}
30
31unsafe impl JavaStrPattern for char {
32 #[inline]
33 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
34 let ch = haystack.chars().next()?;
35 (ch == *self).then(|| ch.len_utf8())
36 }
37
38 #[inline]
39 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
40 let ch = haystack.chars().next_back()?;
41 (ch == *self).then(|| ch.len_utf8())
42 }
43
44 #[inline]
45 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
46 let mut encoded = [0; 4];
47 let encoded = self.encode_utf8(&mut encoded).as_bytes();
48 find(haystack.as_bytes(), encoded).map(|index| (index, encoded.len()))
49 }
50
51 #[inline]
52 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
53 let mut encoded = [0; 4];
54 let encoded = self.encode_utf8(&mut encoded).as_bytes();
55 rfind(haystack.as_bytes(), encoded).map(|index| (index, encoded.len()))
56 }
57}
58
59unsafe impl JavaStrPattern for JavaCodePoint {
60 #[inline]
61 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
62 let ch = haystack.chars().next()?;
63 (ch == *self).then(|| ch.len_utf8())
64 }
65
66 #[inline]
67 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
68 let ch = haystack.chars().next_back()?;
69 (ch == *self).then(|| ch.len_utf8())
70 }
71
72 #[inline]
73 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
74 let mut encoded = [0; 4];
75 let encoded = self.encode_semi_utf8(&mut encoded);
76 find(haystack.as_bytes(), encoded).map(|index| (index, encoded.len()))
77 }
78
79 #[inline]
80 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
81 let mut encoded = [0; 4];
82 let encoded = self.encode_semi_utf8(&mut encoded);
83 rfind(haystack.as_bytes(), encoded).map(|index| (index, encoded.len()))
84 }
85}
86
87unsafe impl JavaStrPattern for &str {
88 #[inline]
89 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
90 haystack
91 .as_bytes()
92 .starts_with(self.as_bytes())
93 .then_some(self.len())
94 }
95
96 #[inline]
97 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
98 haystack
99 .as_bytes()
100 .ends_with(self.as_bytes())
101 .then_some(self.len())
102 }
103
104 #[inline]
105 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
106 find(haystack.as_bytes(), self.as_bytes()).map(|index| (index, self.len()))
107 }
108
109 #[inline]
110 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
111 rfind(haystack.as_bytes(), self.as_bytes()).map(|index| (index, self.len()))
112 }
113}
114
115unsafe impl JavaStrPattern for &JavaStr {
116 #[inline]
117 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
118 haystack
119 .as_bytes()
120 .starts_with(self.as_bytes())
121 .then(|| self.len())
122 }
123
124 #[inline]
125 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
126 haystack
127 .as_bytes()
128 .ends_with(self.as_bytes())
129 .then(|| self.len())
130 }
131
132 #[inline]
133 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
134 find(haystack.as_bytes(), self.as_bytes()).map(|index| (index, self.len()))
135 }
136
137 #[inline]
138 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
139 rfind(haystack.as_bytes(), self.as_bytes()).map(|index| (index, self.len()))
140 }
141}
142
143unsafe impl<F> JavaStrPattern for F
144where
145 F: FnMut(JavaCodePoint) -> bool,
146{
147 #[inline]
148 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
149 let ch = haystack.chars().next()?;
150 self(ch).then(|| ch.len_utf8())
151 }
152
153 #[inline]
154 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
155 let ch = haystack.chars().next_back()?;
156 self(ch).then(|| ch.len_utf8())
157 }
158
159 #[inline]
160 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
161 haystack
162 .char_indices()
163 .find(|(_, ch)| self(*ch))
164 .map(|(index, ch)| (index, ch.len_utf8()))
165 }
166
167 #[inline]
168 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
169 haystack
170 .char_indices()
171 .rfind(|(_, ch)| self(*ch))
172 .map(|(index, ch)| (index, ch.len_utf8()))
173 }
174}
175
176unsafe impl JavaStrPattern for &[char] {
177 #[inline]
178 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
179 let ch = haystack.chars().next()?;
180 self.iter().any(|c| ch == *c).then(|| ch.len_utf8())
181 }
182
183 #[inline]
184 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
185 let ch = haystack.chars().next_back()?;
186 self.iter().any(|c| ch == *c).then(|| ch.len_utf8())
187 }
188
189 #[inline]
190 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
191 haystack
192 .char_indices()
193 .find(|(_, ch)| self.iter().any(|c| *ch == *c))
194 .map(|(index, ch)| (index, ch.len_utf8()))
195 }
196
197 #[inline]
198 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
199 haystack
200 .char_indices()
201 .rfind(|(_, ch)| self.iter().any(|c| *ch == *c))
202 .map(|(index, ch)| (index, ch.len_utf8()))
203 }
204}
205
206unsafe impl JavaStrPattern for &[JavaCodePoint] {
207 #[inline]
208 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
209 let ch = haystack.chars().next()?;
210 self.contains(&ch).then(|| ch.len_utf8())
211 }
212
213 #[inline]
214 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
215 let ch = haystack.chars().next_back()?;
216 self.contains(&ch).then(|| ch.len_utf8())
217 }
218
219 #[inline]
220 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
221 haystack
222 .char_indices()
223 .find(|(_, ch)| self.contains(ch))
224 .map(|(index, ch)| (index, ch.len_utf8()))
225 }
226
227 #[inline]
228 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
229 haystack
230 .char_indices()
231 .rfind(|(_, ch)| self.contains(ch))
232 .map(|(index, ch)| (index, ch.len_utf8()))
233 }
234}
235
236unsafe impl JavaStrPattern for &char {
237 #[inline]
238 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
239 let mut ch = **self;
240 ch.prefix_len_in(haystack)
241 }
242
243 #[inline]
244 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
245 let mut ch = **self;
246 ch.suffix_len_in(haystack)
247 }
248
249 #[inline]
250 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
251 let mut ch = **self;
252 ch.find_in(haystack)
253 }
254
255 #[inline]
256 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
257 let mut ch = **self;
258 ch.rfind_in(haystack)
259 }
260}
261
262unsafe impl JavaStrPattern for &JavaCodePoint {
263 #[inline]
264 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
265 let mut ch = **self;
266 ch.prefix_len_in(haystack)
267 }
268
269 #[inline]
270 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
271 let mut ch = **self;
272 ch.suffix_len_in(haystack)
273 }
274
275 #[inline]
276 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
277 let mut ch = **self;
278 ch.find_in(haystack)
279 }
280
281 #[inline]
282 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
283 let mut ch = **self;
284 ch.rfind_in(haystack)
285 }
286}
287
288unsafe impl JavaStrPattern for &&str {
289 #[inline]
290 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
291 let mut str = **self;
292 str.prefix_len_in(haystack)
293 }
294
295 #[inline]
296 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
297 let mut str = **self;
298 str.suffix_len_in(haystack)
299 }
300
301 #[inline]
302 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
303 let mut str = **self;
304 str.find_in(haystack)
305 }
306
307 #[inline]
308 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
309 let mut str = **self;
310 str.rfind_in(haystack)
311 }
312}
313
314unsafe impl JavaStrPattern for &&JavaStr {
315 #[inline]
316 fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
317 let mut str = **self;
318 str.prefix_len_in(haystack)
319 }
320
321 #[inline]
322 fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option<usize> {
323 let mut str = **self;
324 str.suffix_len_in(haystack)
325 }
326
327 #[inline]
328 fn find_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
329 let mut str = **self;
330 str.find_in(haystack)
331 }
332
333 #[inline]
334 fn rfind_in(&mut self, haystack: &JavaStr) -> Option<(usize, usize)> {
335 let mut str = **self;
336 str.rfind_in(haystack)
337 }
338}
339
340#[inline]
341fn find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
342 if needle.is_empty() {
343 return Some(0);
344 }
345 haystack
346 .windows(needle.len())
347 .position(|window| window == needle)
348}
349
350#[inline]
351fn rfind(haystack: &[u8], needle: &[u8]) -> Option<usize> {
352 if needle.is_empty() {
353 return Some(haystack.len());
354 }
355 haystack
356 .windows(needle.len())
357 .rposition(|window| window == needle)
358}