1use std::fmt::{Debug, Display, Formatter, Write};
2use std::iter::{Chain, Copied, Filter, FlatMap, Flatten, FusedIterator, Map};
3use std::{option, slice};
4
5use crate::validations::{next_code_point, next_code_point_reverse};
6use crate::{CharEscapeIter, JavaCodePoint, JavaStr, JavaStrPattern};
7macro_rules! delegate {
8 (Iterator for $ty:ident $(<$($lt:lifetime),+>)? => $item:ty $(, DoubleEnded = $double_ended:ty)?) => {
9 impl$(<$($lt),+>)? Iterator for $ty$(<$($lt),+>)? {
10 type Item = $item;
11
12 #[inline]
13 fn next(&mut self) -> Option<Self::Item> {
14 self.inner.next()
15 }
16
17 #[inline]
18 fn size_hint(&self) -> (usize, Option<usize>) {
19 self.inner.size_hint()
20 }
21
22 #[inline]
23 fn count(self) -> usize {
24 self.inner.count()
25 }
26
27 #[inline]
28 fn last(self) -> Option<Self::Item> {
29 self.inner.last()
30 }
31
32 #[inline]
33 fn nth(&mut self, n: usize) -> Option<Self::Item> {
34 self.inner.nth(n)
35 }
36
37 #[inline]
38 fn all<F>(&mut self, f: F) -> bool
39 where
40 F: FnMut(Self::Item) -> bool,
41 {
42 self.inner.all(f)
43 }
44
45 #[inline]
46 fn any<F>(&mut self, f: F) -> bool
47 where
48 F: FnMut(Self::Item) -> bool,
49 {
50 self.inner.any(f)
51 }
52
53 #[inline]
54 fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
55 where
56 P: FnMut(&Self::Item) -> bool,
57 {
58 self.inner.find(predicate)
59 }
60
61 #[inline]
62 fn position<P>(&mut self, predicate: P) -> Option<usize>
63 where
64 P: FnMut(Self::Item) -> bool,
65 {
66 self.inner.position(predicate)
67 }
68
69 $(
70 #[inline]
71 fn rposition<P>(&mut self, predicate: P) -> Option<usize>
72 where
73 P: FnMut(Self::Item) -> bool,
74 {
75 let _test: $double_ended = ();
76 self.inner.rposition(predicate)
77 }
78 )?
79 }
80 };
81
82 (DoubleEndedIterator for $ty:ident $(<$($lt:lifetime),+>)?) => {
83 impl$(<$($lt),+>)? DoubleEndedIterator for $ty$(<$($lt),+>)? {
84 #[inline]
85 fn next_back(&mut self) -> Option<Self::Item> {
86 self.inner.next_back()
87 }
88
89 #[inline]
90 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
91 self.inner.nth_back(n)
92 }
93
94 #[inline]
95 fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
96 where
97 P: FnMut(&Self::Item) -> bool,
98 {
99 self.inner.rfind(predicate)
100 }
101 }
102 };
103
104 (ExactSizeIterator for $ty:ident $(<$($lt:lifetime),+>)?) => {
105 impl$(<$($lt),+>)? ExactSizeIterator for $ty$(<$($lt),+>)? {
106 #[inline]
107 fn len(&self) -> usize {
108 self.inner.len()
109 }
110 }
111 };
112
113 (FusedIterator for $ty:ident $(<$($lt:lifetime),+>)?) => {
114 impl$(<$($lt),+>)? FusedIterator for $ty$(<$($lt),+>)? {}
115 };
116
117 (Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator for $ty:ident $(<$($lt:lifetime),+>)? => $item:ty) => {
118 delegate!(Iterator for $ty$(<$($lt),+>)? => $item, DoubleEnded = ());
119 delegate!(DoubleEndedIterator for $ty$(<$($lt),+>)?);
120 delegate!(ExactSizeIterator for $ty$(<$($lt),+>)?);
121 delegate!(FusedIterator for $ty$(<$($lt),+>)?);
122 };
123}
124
125#[must_use]
126#[derive(Clone, Debug)]
127pub struct Bytes<'a> {
128 pub(crate) inner: Copied<slice::Iter<'a, u8>>,
129}
130delegate!(Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator for Bytes<'a> => u8);
131
132#[derive(Clone, Debug)]
133#[must_use]
134pub struct EscapeDebug<'a> {
135 #[allow(clippy::type_complexity)]
136 pub(crate) inner: Chain<
137 Flatten<option::IntoIter<CharEscapeIter>>,
138 FlatMap<Chars<'a>, CharEscapeIter, fn(JavaCodePoint) -> CharEscapeIter>,
139 >,
140}
141delegate!(Iterator for EscapeDebug<'a> => char);
142delegate!(FusedIterator for EscapeDebug<'a>);
143impl Display for EscapeDebug<'_> {
144 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
145 self.clone().try_for_each(|c| f.write_char(c))
146 }
147}
148
149#[derive(Clone, Debug)]
150#[must_use]
151pub struct EscapeDefault<'a> {
152 pub(crate) inner: FlatMap<Chars<'a>, CharEscapeIter, fn(JavaCodePoint) -> CharEscapeIter>,
153}
154delegate!(Iterator for EscapeDefault<'a> => char);
155delegate!(FusedIterator for EscapeDefault<'a>);
156impl Display for EscapeDefault<'_> {
157 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
158 self.clone().try_for_each(|c| f.write_char(c))
159 }
160}
161
162#[derive(Clone, Debug)]
163#[must_use]
164pub struct EscapeUnicode<'a> {
165 pub(crate) inner: FlatMap<Chars<'a>, CharEscapeIter, fn(JavaCodePoint) -> CharEscapeIter>,
166}
167delegate!(Iterator for EscapeUnicode<'a> => char);
168delegate!(FusedIterator for EscapeUnicode<'a>);
169impl Display for EscapeUnicode<'_> {
170 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
171 self.clone().try_for_each(|c| f.write_char(c))
172 }
173}
174
175#[derive(Clone, Debug)]
176#[must_use]
177pub struct Lines<'a> {
178 pub(crate) inner: Map<SplitInclusive<'a, char>, fn(&JavaStr) -> &JavaStr>,
179}
180delegate!(Iterator for Lines<'a> => &'a JavaStr);
181delegate!(DoubleEndedIterator for Lines<'a>);
182delegate!(FusedIterator for Lines<'a>);
183
184#[derive(Clone)]
185#[must_use]
186pub struct Chars<'a> {
187 pub(crate) inner: slice::Iter<'a, u8>,
188}
189
190impl Iterator for Chars<'_> {
191 type Item = JavaCodePoint;
192
193 #[inline]
194 fn next(&mut self) -> Option<Self::Item> {
195 unsafe { next_code_point(&mut self.inner).map(|ch| JavaCodePoint::from_u32_unchecked(ch)) }
199 }
200
201 #[inline]
204 fn size_hint(&self) -> (usize, Option<usize>) {
205 let len = self.inner.len();
206 (len.div_ceil(4), Some(len))
207 }
208
209 #[inline]
210 fn last(mut self) -> Option<JavaCodePoint> {
211 self.next_back()
213 }
214}
215
216impl Debug for Chars<'_> {
217 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
218 write!(f, "Chars(")?;
219 f.debug_list().entries(self.clone()).finish()?;
220 write!(f, ")")?;
221 Ok(())
222 }
223}
224
225impl DoubleEndedIterator for Chars<'_> {
226 #[inline]
227 fn next_back(&mut self) -> Option<Self::Item> {
228 unsafe {
232 next_code_point_reverse(&mut self.inner).map(|ch| JavaCodePoint::from_u32_unchecked(ch))
233 }
234 }
235}
236
237impl FusedIterator for Chars<'_> {}
238
239impl<'a> Chars<'a> {
240 #[inline]
241 #[must_use]
242 pub fn as_str(&self) -> &'a JavaStr {
243 unsafe { JavaStr::from_semi_utf8_unchecked(self.inner.as_slice()) }
246 }
247}
248
249#[derive(Clone, Debug)]
250#[must_use]
251pub struct CharIndices<'a> {
252 pub(crate) front_offset: usize,
253 pub(crate) inner: Chars<'a>,
254}
255
256impl Iterator for CharIndices<'_> {
257 type Item = (usize, JavaCodePoint);
258
259 #[inline]
260 fn next(&mut self) -> Option<(usize, JavaCodePoint)> {
261 let pre_len = self.inner.inner.len();
262 match self.inner.next() {
263 None => None,
264 Some(ch) => {
265 let index = self.front_offset;
266 let len = self.inner.inner.len();
267 self.front_offset += pre_len - len;
268 Some((index, ch))
269 }
270 }
271 }
272
273 #[inline]
274 fn count(self) -> usize {
275 self.inner.count()
276 }
277
278 #[inline]
279 fn size_hint(&self) -> (usize, Option<usize>) {
280 self.inner.size_hint()
281 }
282
283 #[inline]
284 fn last(mut self) -> Option<(usize, JavaCodePoint)> {
285 self.next_back()
287 }
288}
289
290impl DoubleEndedIterator for CharIndices<'_> {
291 #[inline]
292 fn next_back(&mut self) -> Option<(usize, JavaCodePoint)> {
293 self.inner.next_back().map(|ch| {
294 let index = self.front_offset + self.inner.inner.len();
295 (index, ch)
296 })
297 }
298}
299
300impl FusedIterator for CharIndices<'_> {}
301
302impl<'a> CharIndices<'a> {
303 #[inline]
304 #[must_use]
305 pub fn as_str(&self) -> &'a JavaStr {
306 self.inner.as_str()
307 }
308
309 #[inline]
310 #[must_use]
311 pub fn offset(&self) -> usize {
312 self.front_offset
313 }
314}
315
316#[must_use]
317#[derive(Debug, Clone)]
318pub struct Matches<'a, P> {
319 pub(crate) str: &'a JavaStr,
320 pub(crate) pat: P,
321}
322
323impl<'a, P> Iterator for Matches<'a, P>
324where
325 P: JavaStrPattern,
326{
327 type Item = &'a JavaStr;
328
329 #[inline]
330 fn next(&mut self) -> Option<Self::Item> {
331 if let Some((index, len)) = self.pat.find_in(self.str) {
332 let ret = unsafe { self.str.get_unchecked(index..index + len) };
334 self.str = unsafe { self.str.get_unchecked(index + len..) };
335 Some(ret)
336 } else {
337 self.str = Default::default();
338 None
339 }
340 }
341}
342
343impl<P> DoubleEndedIterator for Matches<'_, P>
344where
345 P: JavaStrPattern,
346{
347 #[inline]
348 fn next_back(&mut self) -> Option<Self::Item> {
349 if let Some((index, len)) = self.pat.rfind_in(self.str) {
350 let ret = unsafe { self.str.get_unchecked(index..index + len) };
352 self.str = unsafe { self.str.get_unchecked(..index) };
353 Some(ret)
354 } else {
355 self.str = Default::default();
356 None
357 }
358 }
359}
360
361#[must_use]
362#[derive(Clone, Debug)]
363pub struct RMatches<'a, P> {
364 pub(crate) inner: Matches<'a, P>,
365}
366
367impl<'a, P> Iterator for RMatches<'a, P>
368where
369 P: JavaStrPattern,
370{
371 type Item = &'a JavaStr;
372
373 #[inline]
374 fn next(&mut self) -> Option<Self::Item> {
375 self.inner.next_back()
376 }
377}
378
379impl<P> DoubleEndedIterator for RMatches<'_, P>
380where
381 P: JavaStrPattern,
382{
383 #[inline]
384 fn next_back(&mut self) -> Option<Self::Item> {
385 self.inner.next()
386 }
387}
388
389#[must_use]
390#[derive(Clone, Debug)]
391pub struct MatchIndices<'a, P> {
392 pub(crate) str: &'a JavaStr,
393 pub(crate) start: usize,
394 pub(crate) pat: P,
395}
396
397impl<'a, P> Iterator for MatchIndices<'a, P>
398where
399 P: JavaStrPattern,
400{
401 type Item = (usize, &'a JavaStr);
402
403 #[inline]
404 fn next(&mut self) -> Option<Self::Item> {
405 if let Some((index, len)) = self.pat.find_in(self.str) {
406 let full_index = self.start + index;
407 self.start = full_index + len;
408 let ret = unsafe { self.str.get_unchecked(index..index + len) };
410 self.str = unsafe { self.str.get_unchecked(index + len..) };
411 Some((full_index, ret))
412 } else {
413 self.start += self.str.len();
414 self.str = Default::default();
415 None
416 }
417 }
418}
419
420impl<P> DoubleEndedIterator for MatchIndices<'_, P>
421where
422 P: JavaStrPattern,
423{
424 #[inline]
425 fn next_back(&mut self) -> Option<Self::Item> {
426 if let Some((index, len)) = self.pat.rfind_in(self.str) {
427 let ret = unsafe { self.str.get_unchecked(index..index + len) };
429 self.str = unsafe { self.str.get_unchecked(..index) };
430 Some((self.start + index, ret))
431 } else {
432 self.str = Default::default();
433 None
434 }
435 }
436}
437
438#[derive(Clone, Debug)]
439pub struct RMatchIndices<'a, P> {
440 pub(crate) inner: MatchIndices<'a, P>,
441}
442
443impl<'a, P> Iterator for RMatchIndices<'a, P>
444where
445 P: JavaStrPattern,
446{
447 type Item = (usize, &'a JavaStr);
448
449 #[inline]
450 fn next(&mut self) -> Option<Self::Item> {
451 self.inner.next_back()
452 }
453}
454
455impl<P> DoubleEndedIterator for RMatchIndices<'_, P>
456where
457 P: JavaStrPattern,
458{
459 #[inline]
460 fn next_back(&mut self) -> Option<Self::Item> {
461 self.inner.next()
462 }
463}
464
465#[derive(Clone, Debug)]
466struct SplitHelper<'a, P> {
467 start: usize,
468 end: usize,
469 haystack: &'a JavaStr,
470 pat: P,
471 allow_trailing_empty: bool,
472 finished: bool,
473 had_empty_match: bool,
474}
475
476impl<'a, P> SplitHelper<'a, P>
477where
478 P: JavaStrPattern,
479{
480 #[inline]
481 fn new(haystack: &'a JavaStr, pat: P, allow_trailing_empty: bool) -> Self {
482 Self {
483 start: 0,
484 end: haystack.len(),
485 haystack,
486 pat,
487 allow_trailing_empty,
488 finished: false,
489 had_empty_match: false,
490 }
491 }
492
493 #[inline]
494 fn get_end(&mut self) -> Option<&'a JavaStr> {
495 if !self.finished {
496 self.finished = true;
497
498 if self.allow_trailing_empty || self.end - self.start > 0 {
499 let string = unsafe { self.haystack.get_unchecked(self.start..self.end) };
501 return Some(string);
502 }
503 }
504
505 None
506 }
507
508 #[inline]
509 fn next_match(&mut self) -> Option<(usize, usize)> {
510 let substr = unsafe { self.haystack.get_unchecked(self.start..) };
512
513 let result = if self.had_empty_match {
514 if substr.is_empty() {
518 None
519 } else {
520 let first_char_len = unsafe { substr.chars().next().unwrap_unchecked().len_utf8() };
523 let popped_str = unsafe { substr.get_unchecked(first_char_len..) };
524
525 self.pat
526 .find_in(popped_str)
527 .map(|(index, len)| (index + first_char_len + self.start, len))
528 }
529 } else {
530 self.pat
531 .find_in(substr)
532 .map(|(index, len)| (index + self.start, len))
533 };
534
535 self.had_empty_match = result.is_some_and(|(_, len)| len == 0);
536
537 result
538 }
539
540 #[inline]
541 fn next(&mut self) -> Option<&'a JavaStr> {
542 if self.finished {
543 return None;
544 }
545
546 match self.next_match() {
547 Some((index, len)) => unsafe {
548 let elt = self.haystack.get_unchecked(self.start..index);
550 self.start = index + len;
551 Some(elt)
552 },
553 None => self.get_end(),
554 }
555 }
556
557 #[inline]
558 fn next_inclusive(&mut self) -> Option<&'a JavaStr> {
559 if self.finished {
560 return None;
561 }
562
563 match self.next_match() {
564 Some((index, len)) => unsafe {
565 let elt = self.haystack.get_unchecked(self.start..index + len);
567 self.start = index + len;
568 Some(elt)
569 },
570 None => self.get_end(),
571 }
572 }
573
574 #[inline]
575 fn next_match_back(&mut self) -> Option<(usize, usize)> {
576 let substr = unsafe { self.haystack.get_unchecked(..self.end) };
578
579 let result = if self.had_empty_match {
580 if substr.is_empty() {
584 None
585 } else {
586 let last_char_len =
589 unsafe { substr.chars().next_back().unwrap_unchecked().len_utf8() };
590 let popped_str = unsafe { substr.get_unchecked(..substr.len() - last_char_len) };
591
592 self.pat.rfind_in(popped_str)
593 }
594 } else {
595 self.pat.rfind_in(substr)
596 };
597
598 self.had_empty_match = result.is_some_and(|(_, len)| len == 0);
599
600 result
601 }
602
603 #[inline]
604 fn next_back(&mut self) -> Option<&'a JavaStr> {
605 if self.finished {
606 return None;
607 }
608
609 if !self.allow_trailing_empty {
610 self.allow_trailing_empty = true;
611 match self.next_back() {
612 Some(elt) if !elt.is_empty() => return Some(elt),
613 _ => {
614 if self.finished {
615 return None;
616 }
617 }
618 }
619 }
620
621 match self.next_match_back() {
622 Some((index, len)) => unsafe {
623 let elt = self.haystack.get_unchecked(index + len..self.end);
625 self.end = index;
626 Some(elt)
627 },
628 None => unsafe {
629 self.finished = true;
631 Some(self.haystack.get_unchecked(self.start..self.end))
632 },
633 }
634 }
635
636 #[inline]
637 fn next_back_inclusive(&mut self) -> Option<&'a JavaStr> {
638 if self.finished {
639 return None;
640 }
641
642 if !self.allow_trailing_empty {
643 self.allow_trailing_empty = true;
644 match self.next_back_inclusive() {
645 Some(elt) if !elt.is_empty() => return Some(elt),
646 _ => {
647 if self.finished {
648 return None;
649 }
650 }
651 }
652 }
653
654 match self.next_match_back() {
655 Some((index, len)) => {
656 let elt = unsafe { self.haystack.get_unchecked(index + len..self.end) };
658 self.end = index + len;
659 Some(elt)
660 }
661 None => {
662 self.finished = true;
663 Some(unsafe { self.haystack.get_unchecked(self.start..self.end) })
665 }
666 }
667 }
668}
669
670#[derive(Clone, Debug)]
671pub struct Split<'a, P> {
672 inner: SplitHelper<'a, P>,
673}
674
675impl<'a, P> Split<'a, P>
676where
677 P: JavaStrPattern,
678{
679 #[inline]
680 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
681 Split {
682 inner: SplitHelper::new(haystack, pat, true),
683 }
684 }
685}
686
687impl<'a, P> Iterator for Split<'a, P>
688where
689 P: JavaStrPattern,
690{
691 type Item = &'a JavaStr;
692
693 #[inline]
694 fn next(&mut self) -> Option<Self::Item> {
695 self.inner.next()
696 }
697}
698
699impl<P> DoubleEndedIterator for Split<'_, P>
700where
701 P: JavaStrPattern,
702{
703 #[inline]
704 fn next_back(&mut self) -> Option<Self::Item> {
705 self.inner.next_back()
706 }
707}
708
709impl<P> FusedIterator for Split<'_, P> where P: JavaStrPattern {}
710
711#[derive(Clone, Debug)]
712pub struct RSplit<'a, P> {
713 inner: SplitHelper<'a, P>,
714}
715
716impl<'a, P> RSplit<'a, P>
717where
718 P: JavaStrPattern,
719{
720 #[inline]
721 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
722 RSplit {
723 inner: SplitHelper::new(haystack, pat, true),
724 }
725 }
726}
727
728impl<'a, P> Iterator for RSplit<'a, P>
729where
730 P: JavaStrPattern,
731{
732 type Item = &'a JavaStr;
733
734 #[inline]
735 fn next(&mut self) -> Option<Self::Item> {
736 self.inner.next_back()
737 }
738}
739
740impl<P> DoubleEndedIterator for RSplit<'_, P>
741where
742 P: JavaStrPattern,
743{
744 #[inline]
745 fn next_back(&mut self) -> Option<Self::Item> {
746 self.inner.next()
747 }
748}
749
750impl<P> FusedIterator for RSplit<'_, P> where P: JavaStrPattern {}
751
752#[derive(Clone, Debug)]
753pub struct SplitTerminator<'a, P> {
754 inner: SplitHelper<'a, P>,
755}
756
757impl<'a, P> SplitTerminator<'a, P>
758where
759 P: JavaStrPattern,
760{
761 #[inline]
762 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
763 SplitTerminator {
764 inner: SplitHelper::new(haystack, pat, false),
765 }
766 }
767}
768
769impl<'a, P> Iterator for SplitTerminator<'a, P>
770where
771 P: JavaStrPattern,
772{
773 type Item = &'a JavaStr;
774
775 #[inline]
776 fn next(&mut self) -> Option<Self::Item> {
777 self.inner.next()
778 }
779}
780
781impl<P> DoubleEndedIterator for SplitTerminator<'_, P>
782where
783 P: JavaStrPattern,
784{
785 #[inline]
786 fn next_back(&mut self) -> Option<Self::Item> {
787 self.inner.next_back()
788 }
789}
790
791impl<P> FusedIterator for SplitTerminator<'_, P> where P: JavaStrPattern {}
792
793#[derive(Clone, Debug)]
794pub struct RSplitTerminator<'a, P> {
795 inner: SplitHelper<'a, P>,
796}
797
798impl<'a, P> RSplitTerminator<'a, P>
799where
800 P: JavaStrPattern,
801{
802 #[inline]
803 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
804 RSplitTerminator {
805 inner: SplitHelper::new(haystack, pat, false),
806 }
807 }
808}
809
810impl<'a, P> Iterator for RSplitTerminator<'a, P>
811where
812 P: JavaStrPattern,
813{
814 type Item = &'a JavaStr;
815
816 #[inline]
817 fn next(&mut self) -> Option<Self::Item> {
818 self.inner.next_back()
819 }
820}
821
822impl<P> DoubleEndedIterator for RSplitTerminator<'_, P>
823where
824 P: JavaStrPattern,
825{
826 #[inline]
827 fn next_back(&mut self) -> Option<Self::Item> {
828 self.inner.next()
829 }
830}
831
832impl<P> FusedIterator for RSplitTerminator<'_, P> where P: JavaStrPattern {}
833
834#[derive(Clone, Debug)]
835pub struct SplitInclusive<'a, P> {
836 inner: SplitHelper<'a, P>,
837}
838
839impl<'a, P> SplitInclusive<'a, P>
840where
841 P: JavaStrPattern,
842{
843 #[inline]
844 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
845 SplitInclusive {
846 inner: SplitHelper::new(haystack, pat, false),
847 }
848 }
849}
850
851impl<'a, P> Iterator for SplitInclusive<'a, P>
852where
853 P: JavaStrPattern,
854{
855 type Item = &'a JavaStr;
856
857 #[inline]
858 fn next(&mut self) -> Option<Self::Item> {
859 self.inner.next_inclusive()
860 }
861}
862
863impl<P> DoubleEndedIterator for SplitInclusive<'_, P>
864where
865 P: JavaStrPattern,
866{
867 #[inline]
868 fn next_back(&mut self) -> Option<Self::Item> {
869 self.inner.next_back_inclusive()
870 }
871}
872
873impl<P> FusedIterator for SplitInclusive<'_, P> where P: JavaStrPattern {}
874
875#[derive(Clone, Debug)]
876pub struct SplitN<'a, P> {
877 inner: SplitHelper<'a, P>,
878 count: usize,
879}
880
881impl<'a, P> SplitN<'a, P>
882where
883 P: JavaStrPattern,
884{
885 #[inline]
886 pub(crate) fn new(haystack: &'a JavaStr, pat: P, count: usize) -> Self {
887 SplitN {
888 inner: SplitHelper::new(haystack, pat, true),
889 count,
890 }
891 }
892}
893
894impl<'a, P> Iterator for SplitN<'a, P>
895where
896 P: JavaStrPattern,
897{
898 type Item = &'a JavaStr;
899
900 #[inline]
901 fn next(&mut self) -> Option<Self::Item> {
902 match self.count {
903 0 => None,
904 1 => {
905 self.count = 0;
906 self.inner.get_end()
907 }
908 _ => {
909 self.count -= 1;
910 self.inner.next()
911 }
912 }
913 }
914}
915
916impl<P> FusedIterator for SplitN<'_, P> where P: JavaStrPattern {}
917
918#[derive(Clone, Debug)]
919pub struct RSplitN<'a, P> {
920 inner: SplitHelper<'a, P>,
921 count: usize,
922}
923
924impl<'a, P> RSplitN<'a, P>
925where
926 P: JavaStrPattern,
927{
928 #[inline]
929 pub(crate) fn new(haystack: &'a JavaStr, pat: P, count: usize) -> Self {
930 RSplitN {
931 inner: SplitHelper::new(haystack, pat, true),
932 count,
933 }
934 }
935}
936
937impl<'a, P> Iterator for RSplitN<'a, P>
938where
939 P: JavaStrPattern,
940{
941 type Item = &'a JavaStr;
942
943 #[inline]
944 fn next(&mut self) -> Option<Self::Item> {
945 match self.count {
946 0 => None,
947 1 => {
948 self.count = 0;
949 self.inner.get_end()
950 }
951 _ => {
952 self.count -= 1;
953 self.inner.next_back()
954 }
955 }
956 }
957}
958
959impl<P> FusedIterator for RSplitN<'_, P> where P: JavaStrPattern {}
960
961#[derive(Clone, Debug)]
962pub struct SplitAsciiWhitespace<'a> {
963 #[allow(clippy::type_complexity)]
964 pub(crate) inner: Map<
965 Filter<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&&[u8]) -> bool>,
966 fn(&[u8]) -> &JavaStr,
967 >,
968}
969delegate!(Iterator for SplitAsciiWhitespace<'a> => &'a JavaStr);
970delegate!(DoubleEndedIterator for SplitAsciiWhitespace<'a>);
971delegate!(FusedIterator for SplitAsciiWhitespace<'a>);
972
973#[derive(Clone, Debug)]
974pub struct SplitWhitespace<'a> {
975 #[allow(clippy::type_complexity)]
976 pub(crate) inner: Filter<Split<'a, fn(JavaCodePoint) -> bool>, fn(&&JavaStr) -> bool>,
977}
978delegate!(Iterator for SplitWhitespace<'a> => &'a JavaStr);
979delegate!(DoubleEndedIterator for SplitWhitespace<'a>);
980delegate!(FusedIterator for SplitWhitespace<'a>);