this repo has no description
at main 974 lines 25 kB view raw
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 // SAFETY: `JavaStr` invariant says `self.inner` is a semi-valid UTF-8 string 196 // and the resulting `ch` is a valid Unicode Scalar Value or surrogate 197 // code point. 198 unsafe { next_code_point(&mut self.inner).map(|ch| JavaCodePoint::from_u32_unchecked(ch)) } 199 } 200 201 // TODO: std has an optimized count impl 202 203 #[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 // No need to go through the entire string. 212 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 // SAFETY: `JavaStr` invariant says `self.inner` is a semi-valid UTF-8 string 229 // and the resulting `ch` is a valid Unicode Scalar Value or surrogate 230 // code point. 231 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 // SAFETY: `Chars` is only made from a JavaStr, which guarantees the iter is 244 // semi-valid UTF-8. 245 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 // No need to go through the entire string. 286 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 // SAFETY: pattern returns valid indices 327 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 // SAFETY: pattern returns valid indices 345 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 // SAFETY: pattern returns valid indices 403 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 // SAFETY: pattern returns valid indices 422 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 // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. 494 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 // SAFETY: `self.start` always lies on a unicode boundary. 505 let substr = unsafe { self.haystack.get_unchecked(self.start..) }; 506 507 let result = if self.had_empty_match { 508 // if we had an empty match before, we are going to find the empty match again. 509 // don't do that, search from the next index along. 510 511 if substr.is_empty() { 512 None 513 } else { 514 // SAFETY: we can pop the string because we already checked if the string is 515 // empty above 516 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 // SAFETY: pattern guarantees valid indices 543 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 // SAFETY: pattern guarantees valid indices 560 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 // SAFETY: `self.end` always lies on a unicode boundary. 571 let substr = unsafe { self.haystack.get_unchecked(..self.end) }; 572 573 let result = if self.had_empty_match { 574 // if we had an empty match before, we are going to find the empty match again. 575 // don't do that, search from the next index along. 576 577 if substr.is_empty() { 578 None 579 } else { 580 // SAFETY: we can pop the string because we already checked if the string is 581 // empty above 582 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 // SAFETY: pattern guarantees valid indices 618 let elt = self.haystack.get_unchecked(index + len..self.end); 619 self.end = index; 620 Some(elt) 621 }, 622 None => unsafe { 623 // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. 624 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 // SAFETY: pattern guarantees valid indices 651 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 // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. 658 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>);