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
310#[must_use]
311#[derive(Debug, Clone)]
312pub struct Matches<'a, P> {
313 pub(crate) str: &'a JavaStr,
314 pub(crate) pat: P,
315}
316
317impl<'a, P> Iterator for Matches<'a, P>
318where
319 P: JavaStrPattern,
320{
321 type Item = &'a JavaStr;
322
323 #[inline]
324 fn next(&mut self) -> Option<Self::Item> {
325 if let Some((index, len)) = self.pat.find_in(self.str) {
326 let ret = unsafe { self.str.get_unchecked(index..index + len) };
328 self.str = unsafe { self.str.get_unchecked(index + len..) };
329 Some(ret)
330 } else {
331 self.str = Default::default();
332 None
333 }
334 }
335}
336
337impl<P> DoubleEndedIterator for Matches<'_, P>
338where
339 P: JavaStrPattern,
340{
341 #[inline]
342 fn next_back(&mut self) -> Option<Self::Item> {
343 if let Some((index, len)) = self.pat.rfind_in(self.str) {
344 let ret = unsafe { self.str.get_unchecked(index..index + len) };
346 self.str = unsafe { self.str.get_unchecked(..index) };
347 Some(ret)
348 } else {
349 self.str = Default::default();
350 None
351 }
352 }
353}
354
355#[must_use]
356#[derive(Clone, Debug)]
357pub struct RMatches<'a, P> {
358 pub(crate) inner: Matches<'a, P>,
359}
360
361impl<'a, P> Iterator for RMatches<'a, P>
362where
363 P: JavaStrPattern,
364{
365 type Item = &'a JavaStr;
366
367 #[inline]
368 fn next(&mut self) -> Option<Self::Item> {
369 self.inner.next_back()
370 }
371}
372
373impl<P> DoubleEndedIterator for RMatches<'_, P>
374where
375 P: JavaStrPattern,
376{
377 #[inline]
378 fn next_back(&mut self) -> Option<Self::Item> {
379 self.inner.next()
380 }
381}
382
383#[must_use]
384#[derive(Clone, Debug)]
385pub struct MatchIndices<'a, P> {
386 pub(crate) str: &'a JavaStr,
387 pub(crate) start: usize,
388 pub(crate) pat: P,
389}
390
391impl<'a, P> Iterator for MatchIndices<'a, P>
392where
393 P: JavaStrPattern,
394{
395 type Item = (usize, &'a JavaStr);
396
397 #[inline]
398 fn next(&mut self) -> Option<Self::Item> {
399 if let Some((index, len)) = self.pat.find_in(self.str) {
400 let full_index = self.start + index;
401 self.start = full_index + len;
402 let ret = unsafe { self.str.get_unchecked(index..index + len) };
404 self.str = unsafe { self.str.get_unchecked(index + len..) };
405 Some((full_index, ret))
406 } else {
407 self.start += self.str.len();
408 self.str = Default::default();
409 None
410 }
411 }
412}
413
414impl<P> DoubleEndedIterator for MatchIndices<'_, P>
415where
416 P: JavaStrPattern,
417{
418 #[inline]
419 fn next_back(&mut self) -> Option<Self::Item> {
420 if let Some((index, len)) = self.pat.rfind_in(self.str) {
421 let ret = unsafe { self.str.get_unchecked(index..index + len) };
423 self.str = unsafe { self.str.get_unchecked(..index) };
424 Some((self.start + index, ret))
425 } else {
426 self.str = Default::default();
427 None
428 }
429 }
430}
431
432#[derive(Clone, Debug)]
433pub struct RMatchIndices<'a, P> {
434 pub(crate) inner: MatchIndices<'a, P>,
435}
436
437impl<'a, P> Iterator for RMatchIndices<'a, P>
438where
439 P: JavaStrPattern,
440{
441 type Item = (usize, &'a JavaStr);
442
443 #[inline]
444 fn next(&mut self) -> Option<Self::Item> {
445 self.inner.next_back()
446 }
447}
448
449impl<P> DoubleEndedIterator for RMatchIndices<'_, P>
450where
451 P: JavaStrPattern,
452{
453 #[inline]
454 fn next_back(&mut self) -> Option<Self::Item> {
455 self.inner.next()
456 }
457}
458
459#[derive(Clone, Debug)]
460struct SplitHelper<'a, P> {
461 start: usize,
462 end: usize,
463 haystack: &'a JavaStr,
464 pat: P,
465 allow_trailing_empty: bool,
466 finished: bool,
467 had_empty_match: bool,
468}
469
470impl<'a, P> SplitHelper<'a, P>
471where
472 P: JavaStrPattern,
473{
474 #[inline]
475 fn new(haystack: &'a JavaStr, pat: P, allow_trailing_empty: bool) -> Self {
476 Self {
477 start: 0,
478 end: haystack.len(),
479 haystack,
480 pat,
481 allow_trailing_empty,
482 finished: false,
483 had_empty_match: false,
484 }
485 }
486
487 #[inline]
488 fn get_end(&mut self) -> Option<&'a JavaStr> {
489 if !self.finished {
490 self.finished = true;
491
492 if self.allow_trailing_empty || self.end - self.start > 0 {
493 let string = unsafe { self.haystack.get_unchecked(self.start..self.end) };
495 return Some(string);
496 }
497 }
498
499 None
500 }
501
502 #[inline]
503 fn next_match(&mut self) -> Option<(usize, usize)> {
504 let substr = unsafe { self.haystack.get_unchecked(self.start..) };
506
507 let result = if self.had_empty_match {
508 if substr.is_empty() {
512 None
513 } else {
514 let first_char_len = unsafe { substr.chars().next().unwrap_unchecked().len_utf8() };
517 let popped_str = unsafe { substr.get_unchecked(first_char_len..) };
518
519 self.pat
520 .find_in(popped_str)
521 .map(|(index, len)| (index + first_char_len + self.start, len))
522 }
523 } else {
524 self.pat
525 .find_in(substr)
526 .map(|(index, len)| (index + self.start, len))
527 };
528
529 self.had_empty_match = result.is_some_and(|(_, len)| len == 0);
530
531 result
532 }
533
534 #[inline]
535 fn next(&mut self) -> Option<&'a JavaStr> {
536 if self.finished {
537 return None;
538 }
539
540 match self.next_match() {
541 Some((index, len)) => unsafe {
542 let elt = self.haystack.get_unchecked(self.start..index);
544 self.start = index + len;
545 Some(elt)
546 },
547 None => self.get_end(),
548 }
549 }
550
551 #[inline]
552 fn next_inclusive(&mut self) -> Option<&'a JavaStr> {
553 if self.finished {
554 return None;
555 }
556
557 match self.next_match() {
558 Some((index, len)) => unsafe {
559 let elt = self.haystack.get_unchecked(self.start..index + len);
561 self.start = index + len;
562 Some(elt)
563 },
564 None => self.get_end(),
565 }
566 }
567
568 #[inline]
569 fn next_match_back(&mut self) -> Option<(usize, usize)> {
570 let substr = unsafe { self.haystack.get_unchecked(..self.end) };
572
573 let result = if self.had_empty_match {
574 if substr.is_empty() {
578 None
579 } else {
580 let last_char_len =
583 unsafe { substr.chars().next_back().unwrap_unchecked().len_utf8() };
584 let popped_str = unsafe { substr.get_unchecked(..substr.len() - last_char_len) };
585
586 self.pat.rfind_in(popped_str)
587 }
588 } else {
589 self.pat.rfind_in(substr)
590 };
591
592 self.had_empty_match = result.is_some_and(|(_, len)| len == 0);
593
594 result
595 }
596
597 #[inline]
598 fn next_back(&mut self) -> Option<&'a JavaStr> {
599 if self.finished {
600 return None;
601 }
602
603 if !self.allow_trailing_empty {
604 self.allow_trailing_empty = true;
605 match self.next_back() {
606 Some(elt) if !elt.is_empty() => return Some(elt),
607 _ => {
608 if self.finished {
609 return None;
610 }
611 }
612 }
613 }
614
615 match self.next_match_back() {
616 Some((index, len)) => unsafe {
617 let elt = self.haystack.get_unchecked(index + len..self.end);
619 self.end = index;
620 Some(elt)
621 },
622 None => unsafe {
623 self.finished = true;
625 Some(self.haystack.get_unchecked(self.start..self.end))
626 },
627 }
628 }
629
630 #[inline]
631 fn next_back_inclusive(&mut self) -> Option<&'a JavaStr> {
632 if self.finished {
633 return None;
634 }
635
636 if !self.allow_trailing_empty {
637 self.allow_trailing_empty = true;
638 match self.next_back_inclusive() {
639 Some(elt) if !elt.is_empty() => return Some(elt),
640 _ => {
641 if self.finished {
642 return None;
643 }
644 }
645 }
646 }
647
648 match self.next_match_back() {
649 Some((index, len)) => {
650 let elt = unsafe { self.haystack.get_unchecked(index + len..self.end) };
652 self.end = index + len;
653 Some(elt)
654 }
655 None => {
656 self.finished = true;
657 Some(unsafe { self.haystack.get_unchecked(self.start..self.end) })
659 }
660 }
661 }
662}
663
664#[derive(Clone, Debug)]
665pub struct Split<'a, P> {
666 inner: SplitHelper<'a, P>,
667}
668
669impl<'a, P> Split<'a, P>
670where
671 P: JavaStrPattern,
672{
673 #[inline]
674 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
675 Split {
676 inner: SplitHelper::new(haystack, pat, true),
677 }
678 }
679}
680
681impl<'a, P> Iterator for Split<'a, P>
682where
683 P: JavaStrPattern,
684{
685 type Item = &'a JavaStr;
686
687 #[inline]
688 fn next(&mut self) -> Option<Self::Item> {
689 self.inner.next()
690 }
691}
692
693impl<P> DoubleEndedIterator for Split<'_, P>
694where
695 P: JavaStrPattern,
696{
697 #[inline]
698 fn next_back(&mut self) -> Option<Self::Item> {
699 self.inner.next_back()
700 }
701}
702
703impl<P> FusedIterator for Split<'_, P> where P: JavaStrPattern {}
704
705#[derive(Clone, Debug)]
706pub struct RSplit<'a, P> {
707 inner: SplitHelper<'a, P>,
708}
709
710impl<'a, P> RSplit<'a, P>
711where
712 P: JavaStrPattern,
713{
714 #[inline]
715 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
716 RSplit {
717 inner: SplitHelper::new(haystack, pat, true),
718 }
719 }
720}
721
722impl<'a, P> Iterator for RSplit<'a, P>
723where
724 P: JavaStrPattern,
725{
726 type Item = &'a JavaStr;
727
728 #[inline]
729 fn next(&mut self) -> Option<Self::Item> {
730 self.inner.next_back()
731 }
732}
733
734impl<P> DoubleEndedIterator for RSplit<'_, P>
735where
736 P: JavaStrPattern,
737{
738 #[inline]
739 fn next_back(&mut self) -> Option<Self::Item> {
740 self.inner.next()
741 }
742}
743
744impl<P> FusedIterator for RSplit<'_, P> where P: JavaStrPattern {}
745
746#[derive(Clone, Debug)]
747pub struct SplitTerminator<'a, P> {
748 inner: SplitHelper<'a, P>,
749}
750
751impl<'a, P> SplitTerminator<'a, P>
752where
753 P: JavaStrPattern,
754{
755 #[inline]
756 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
757 SplitTerminator {
758 inner: SplitHelper::new(haystack, pat, false),
759 }
760 }
761}
762
763impl<'a, P> Iterator for SplitTerminator<'a, P>
764where
765 P: JavaStrPattern,
766{
767 type Item = &'a JavaStr;
768
769 #[inline]
770 fn next(&mut self) -> Option<Self::Item> {
771 self.inner.next()
772 }
773}
774
775impl<P> DoubleEndedIterator for SplitTerminator<'_, P>
776where
777 P: JavaStrPattern,
778{
779 #[inline]
780 fn next_back(&mut self) -> Option<Self::Item> {
781 self.inner.next_back()
782 }
783}
784
785impl<P> FusedIterator for SplitTerminator<'_, P> where P: JavaStrPattern {}
786
787#[derive(Clone, Debug)]
788pub struct RSplitTerminator<'a, P> {
789 inner: SplitHelper<'a, P>,
790}
791
792impl<'a, P> RSplitTerminator<'a, P>
793where
794 P: JavaStrPattern,
795{
796 #[inline]
797 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
798 RSplitTerminator {
799 inner: SplitHelper::new(haystack, pat, false),
800 }
801 }
802}
803
804impl<'a, P> Iterator for RSplitTerminator<'a, P>
805where
806 P: JavaStrPattern,
807{
808 type Item = &'a JavaStr;
809
810 #[inline]
811 fn next(&mut self) -> Option<Self::Item> {
812 self.inner.next_back()
813 }
814}
815
816impl<P> DoubleEndedIterator for RSplitTerminator<'_, P>
817where
818 P: JavaStrPattern,
819{
820 #[inline]
821 fn next_back(&mut self) -> Option<Self::Item> {
822 self.inner.next()
823 }
824}
825
826impl<P> FusedIterator for RSplitTerminator<'_, P> where P: JavaStrPattern {}
827
828#[derive(Clone, Debug)]
829pub struct SplitInclusive<'a, P> {
830 inner: SplitHelper<'a, P>,
831}
832
833impl<'a, P> SplitInclusive<'a, P>
834where
835 P: JavaStrPattern,
836{
837 #[inline]
838 pub(crate) fn new(haystack: &'a JavaStr, pat: P) -> Self {
839 SplitInclusive {
840 inner: SplitHelper::new(haystack, pat, false),
841 }
842 }
843}
844
845impl<'a, P> Iterator for SplitInclusive<'a, P>
846where
847 P: JavaStrPattern,
848{
849 type Item = &'a JavaStr;
850
851 #[inline]
852 fn next(&mut self) -> Option<Self::Item> {
853 self.inner.next_inclusive()
854 }
855}
856
857impl<P> DoubleEndedIterator for SplitInclusive<'_, P>
858where
859 P: JavaStrPattern,
860{
861 #[inline]
862 fn next_back(&mut self) -> Option<Self::Item> {
863 self.inner.next_back_inclusive()
864 }
865}
866
867impl<P> FusedIterator for SplitInclusive<'_, P> where P: JavaStrPattern {}
868
869#[derive(Clone, Debug)]
870pub struct SplitN<'a, P> {
871 inner: SplitHelper<'a, P>,
872 count: usize,
873}
874
875impl<'a, P> SplitN<'a, P>
876where
877 P: JavaStrPattern,
878{
879 #[inline]
880 pub(crate) fn new(haystack: &'a JavaStr, pat: P, count: usize) -> Self {
881 SplitN {
882 inner: SplitHelper::new(haystack, pat, true),
883 count,
884 }
885 }
886}
887
888impl<'a, P> Iterator for SplitN<'a, P>
889where
890 P: JavaStrPattern,
891{
892 type Item = &'a JavaStr;
893
894 #[inline]
895 fn next(&mut self) -> Option<Self::Item> {
896 match self.count {
897 0 => None,
898 1 => {
899 self.count = 0;
900 self.inner.get_end()
901 }
902 _ => {
903 self.count -= 1;
904 self.inner.next()
905 }
906 }
907 }
908}
909
910impl<P> FusedIterator for SplitN<'_, P> where P: JavaStrPattern {}
911
912#[derive(Clone, Debug)]
913pub struct RSplitN<'a, P> {
914 inner: SplitHelper<'a, P>,
915 count: usize,
916}
917
918impl<'a, P> RSplitN<'a, P>
919where
920 P: JavaStrPattern,
921{
922 #[inline]
923 pub(crate) fn new(haystack: &'a JavaStr, pat: P, count: usize) -> Self {
924 RSplitN {
925 inner: SplitHelper::new(haystack, pat, true),
926 count,
927 }
928 }
929}
930
931impl<'a, P> Iterator for RSplitN<'a, P>
932where
933 P: JavaStrPattern,
934{
935 type Item = &'a JavaStr;
936
937 #[inline]
938 fn next(&mut self) -> Option<Self::Item> {
939 match self.count {
940 0 => None,
941 1 => {
942 self.count = 0;
943 self.inner.get_end()
944 }
945 _ => {
946 self.count -= 1;
947 self.inner.next_back()
948 }
949 }
950 }
951}
952
953impl<P> FusedIterator for RSplitN<'_, P> where P: JavaStrPattern {}
954
955#[derive(Clone, Debug)]
956pub struct SplitAsciiWhitespace<'a> {
957 #[allow(clippy::type_complexity)]
958 pub(crate) inner: Map<
959 Filter<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&&[u8]) -> bool>,
960 fn(&[u8]) -> &JavaStr,
961 >,
962}
963delegate!(Iterator for SplitAsciiWhitespace<'a> => &'a JavaStr);
964delegate!(DoubleEndedIterator for SplitAsciiWhitespace<'a>);
965delegate!(FusedIterator for SplitAsciiWhitespace<'a>);
966
967#[derive(Clone, Debug)]
968pub struct SplitWhitespace<'a> {
969 #[allow(clippy::type_complexity)]
970 pub(crate) inner: Filter<Split<'a, fn(JavaCodePoint) -> bool>, fn(&&JavaStr) -> bool>,
971}
972delegate!(Iterator for SplitWhitespace<'a> => &'a JavaStr);
973delegate!(DoubleEndedIterator for SplitWhitespace<'a>);
974delegate!(FusedIterator for SplitWhitespace<'a>);