java_string/
pattern.rs

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
21/// # Safety
22///
23/// Methods in this trait must only return indexes that are on char boundaries
24pub 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}