@@ -563,7 +563,7 @@ pub(super) struct SplitInternal<'a, P: Pattern<'a>> {
563
563
pub ( super ) start : usize ,
564
564
pub ( super ) end : usize ,
565
565
pub ( super ) matcher : P :: Searcher ,
566
- pub ( super ) allow_trailing_empty : bool ,
566
+ pub ( super ) allow_bookending_empty : bool ,
567
567
pub ( super ) finished : bool ,
568
568
}
569
569
@@ -576,7 +576,7 @@ where
576
576
. field ( "start" , & self . start )
577
577
. field ( "end" , & self . end )
578
578
. field ( "matcher" , & self . matcher )
579
- . field ( "allow_trailing_empty " , & self . allow_trailing_empty )
579
+ . field ( "allow_bookending_empty " , & self . allow_bookending_empty )
580
580
. field ( "finished" , & self . finished )
581
581
. finish ( )
582
582
}
@@ -585,7 +585,7 @@ where
585
585
impl < ' a , P : Pattern < ' a > > SplitInternal < ' a , P > {
586
586
#[ inline]
587
587
fn get_end ( & mut self ) -> Option < & ' a str > {
588
- if !self . finished && ( self . allow_trailing_empty || self . end - self . start > 0 ) {
588
+ if !self . finished && ( self . allow_bookending_empty || self . end - self . start > 0 ) {
589
589
self . finished = true ;
590
590
// SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
591
591
unsafe {
@@ -635,6 +635,38 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
635
635
}
636
636
}
637
637
638
+ #[ inline]
639
+ fn next_left_inclusive ( & mut self ) -> Option < & ' a str > {
640
+ if self . finished {
641
+ return None ;
642
+ }
643
+
644
+ if !self . allow_bookending_empty {
645
+ self . allow_bookending_empty = true ;
646
+ match self . next_left_inclusive ( ) {
647
+ Some ( elt) if !elt. is_empty ( ) => return Some ( elt) ,
648
+ _ => {
649
+ if self . finished {
650
+ return None ;
651
+ }
652
+ }
653
+ }
654
+ }
655
+
656
+ let haystack = self . matcher . haystack ( ) ;
657
+ match self . matcher . next_match ( ) {
658
+ // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
659
+ // and self.start is either the start of the original string,
660
+ // or `b` was assigned to it, so it also lies on unicode boundary.
661
+ Some ( ( b, _) ) => unsafe {
662
+ let elt = haystack. get_unchecked ( self . start ..b) ;
663
+ self . start = b;
664
+ Some ( elt)
665
+ } ,
666
+ None => self . get_end ( ) ,
667
+ }
668
+ }
669
+
638
670
#[ inline]
639
671
fn next_back ( & mut self ) -> Option < & ' a str >
640
672
where
@@ -644,8 +676,8 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
644
676
return None ;
645
677
}
646
678
647
- if !self . allow_trailing_empty {
648
- self . allow_trailing_empty = true ;
679
+ if !self . allow_bookending_empty {
680
+ self . allow_bookending_empty = true ;
649
681
match self . next_back ( ) {
650
682
Some ( elt) if !elt. is_empty ( ) => return Some ( elt) ,
651
683
_ => {
@@ -681,8 +713,8 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
681
713
return None ;
682
714
}
683
715
684
- if !self . allow_trailing_empty {
685
- self . allow_trailing_empty = true ;
716
+ if !self . allow_bookending_empty {
717
+ self . allow_bookending_empty = true ;
686
718
match self . next_back_inclusive ( ) {
687
719
Some ( elt) if !elt. is_empty ( ) => return Some ( elt) ,
688
720
_ => {
@@ -715,6 +747,40 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
715
747
}
716
748
}
717
749
750
+ #[ inline]
751
+ fn next_back_left_inclusive ( & mut self ) -> Option < & ' a str >
752
+ where
753
+ P :: Searcher : ReverseSearcher < ' a > ,
754
+ {
755
+ if self . finished {
756
+ return None ;
757
+ }
758
+
759
+ let haystack = self . matcher . haystack ( ) ;
760
+ match self . matcher . next_match_back ( ) {
761
+ // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
762
+ // and self.end is either the end of the original string,
763
+ // or `b` was assigned to it, so it also lies on unicode boundary.
764
+ Some ( ( b, _) ) => unsafe {
765
+ let elt = haystack. get_unchecked ( b..self . end ) ;
766
+ self . end = b;
767
+ if self . start == b {
768
+ self . finished = true ;
769
+ }
770
+ Some ( elt)
771
+ } ,
772
+ // SAFETY: self.start is either the start of the original string,
773
+ // or start of a substring that represents the part of the string that hasn't
774
+ // iterated yet. Either way, it is guaranteed to lie on unicode boundary.
775
+ // self.end is either the end of the original string,
776
+ // or `b` was assigned to it, so it also lies on unicode boundary.
777
+ None => unsafe {
778
+ self . finished = true ;
779
+ Some ( haystack. get_unchecked ( self . start ..self . end ) )
780
+ } ,
781
+ }
782
+ }
783
+
718
784
#[ inline]
719
785
fn as_str ( & self ) -> & ' a str {
720
786
// `Self::get_end` doesn't change `self.start`
@@ -1190,18 +1256,6 @@ pub struct SplitAsciiWhitespace<'a> {
1190
1256
Map < Filter < SliceSplit < ' a , u8 , IsAsciiWhitespace > , BytesIsNotEmpty > , UnsafeBytesToStr > ,
1191
1257
}
1192
1258
1193
- /// An iterator over the substrings of a string,
1194
- /// terminated by a substring matching to a predicate function
1195
- /// Unlike `Split`, it contains the matched part as a terminator
1196
- /// of the subslice.
1197
- ///
1198
- /// This struct is created by the [`split_inclusive`] method on [`str`].
1199
- /// See its documentation for more.
1200
- ///
1201
- /// [`split_inclusive`]: str::split_inclusive
1202
- #[ stable( feature = "split_inclusive" , since = "1.51.0" ) ]
1203
- pub struct SplitInclusive < ' a , P : Pattern < ' a > > ( pub ( super ) SplitInternal < ' a , P > ) ;
1204
-
1205
1259
#[ stable( feature = "split_whitespace" , since = "1.1.0" ) ]
1206
1260
impl < ' a > Iterator for SplitWhitespace < ' a > {
1207
1261
type Item = & ' a str ;
@@ -1319,6 +1373,18 @@ impl<'a> SplitAsciiWhitespace<'a> {
1319
1373
}
1320
1374
}
1321
1375
1376
+ /// An iterator over the substrings of a string,
1377
+ /// terminated by a substring matching to a predicate function
1378
+ /// Unlike `Split`, it contains the matched part as a terminator
1379
+ /// of the subslice.
1380
+ ///
1381
+ /// This struct is created by the [`split_inclusive`] method on [`str`].
1382
+ /// See its documentation for more.
1383
+ ///
1384
+ /// [`split_inclusive`]: str::split_inclusive
1385
+ #[ stable( feature = "split_inclusive" , since = "1.51.0" ) ]
1386
+ pub struct SplitInclusive < ' a , P : Pattern < ' a > > ( pub ( super ) SplitInternal < ' a , P > ) ;
1387
+
1322
1388
#[ stable( feature = "split_inclusive" , since = "1.51.0" ) ]
1323
1389
impl < ' a , P : Pattern < ' a > > Iterator for SplitInclusive < ' a , P > {
1324
1390
type Item = & ' a str ;
@@ -1378,6 +1444,78 @@ impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
1378
1444
}
1379
1445
}
1380
1446
1447
+ /// An iterator over the substrings of a string,
1448
+ /// terminated by a substring matching to a predicate function
1449
+ /// Unlike `Split`, it contains the matched part as an initiator
1450
+ /// of the subslice.
1451
+ ///
1452
+ /// This struct is created by the [`split_left_inclusive`] method on [`str`].
1453
+ /// See its documentation for more.
1454
+ ///
1455
+ /// [`split_left_inclusive`]: str::split_left_inclusive
1456
+ #[ unstable( feature = "split_left_inclusive" , issue = "none" ) ]
1457
+ pub struct SplitLeftInclusive < ' a , P : Pattern < ' a > > ( pub ( super ) SplitInternal < ' a , P > ) ;
1458
+
1459
+ #[ unstable( feature = "split_left_inclusive" , issue = "none" ) ]
1460
+ impl < ' a , P : Pattern < ' a > > Iterator for SplitLeftInclusive < ' a , P > {
1461
+ type Item = & ' a str ;
1462
+
1463
+ #[ inline]
1464
+ fn next ( & mut self ) -> Option < & ' a str > {
1465
+ self . 0 . next_left_inclusive ( )
1466
+ }
1467
+ }
1468
+
1469
+ #[ unstable( feature = "split_left_inclusive" , issue = "none" ) ]
1470
+ impl < ' a , P : Pattern < ' a , Searcher : fmt:: Debug > > fmt:: Debug for SplitLeftInclusive < ' a , P > {
1471
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1472
+ f. debug_struct ( "SplitLeftInclusive" ) . field ( "0" , & self . 0 ) . finish ( )
1473
+ }
1474
+ }
1475
+
1476
+ // FIXME(#26925) Remove in favor of `#[derive(Clone)]`
1477
+ #[ unstable( feature = "split_left_inclusive" , issue = "none" ) ]
1478
+ impl < ' a , P : Pattern < ' a , Searcher : Clone > > Clone for SplitLeftInclusive < ' a , P > {
1479
+ fn clone ( & self ) -> Self {
1480
+ SplitLeftInclusive ( self . 0 . clone ( ) )
1481
+ }
1482
+ }
1483
+
1484
+ #[ unstable( feature = "split_left_inclusive" , issue = "none" ) ]
1485
+ impl < ' a , P : Pattern < ' a , Searcher : ReverseSearcher < ' a > > > DoubleEndedIterator
1486
+ for SplitLeftInclusive < ' a , P >
1487
+ {
1488
+ #[ inline]
1489
+ fn next_back ( & mut self ) -> Option < & ' a str > {
1490
+ self . 0 . next_back_left_inclusive ( )
1491
+ }
1492
+ }
1493
+
1494
+ #[ unstable( feature = "split_left_inclusive" , issue = "none" ) ]
1495
+ impl < ' a , P : Pattern < ' a > > FusedIterator for SplitLeftInclusive < ' a , P > { }
1496
+
1497
+ impl < ' a , P : Pattern < ' a > > SplitLeftInclusive < ' a , P > {
1498
+ /// Returns remainder of the splitted string
1499
+ ///
1500
+ /// # Examples
1501
+ ///
1502
+ /// ```
1503
+ /// #![feature(str_split_inclusive_as_str)]
1504
+ /// #![feature(split_left_inclusive)]
1505
+ /// let mut split = "Mary had a little lamb".split_left_inclusive(' ');
1506
+ /// assert_eq!(split.as_str(), "Mary had a little lamb");
1507
+ /// split.next();
1508
+ /// assert_eq!(split.as_str(), " had a little lamb");
1509
+ /// split.by_ref().for_each(drop);
1510
+ /// assert_eq!(split.as_str(), "");
1511
+ /// ```
1512
+ #[ inline]
1513
+ #[ unstable( feature = "str_split_inclusive_as_str" , issue = "77998" ) ]
1514
+ pub fn as_str ( & self ) -> & ' a str {
1515
+ self . 0 . as_str ( )
1516
+ }
1517
+ }
1518
+
1381
1519
/// An iterator of [`u16`] over the string encoded as UTF-16.
1382
1520
///
1383
1521
/// This struct is created by the [`encode_utf16`] method on [`str`].
0 commit comments