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