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        (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}