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