Skip to content

Commit 977df43

Browse files
authored
Rollup merge of #75265 - WaffleLapkin:str_split_as_str, r=dtolnay
Add `str::{Split,RSplit,SplitN,RSplitN,SplitTerminator,RSplitTerminator,SplitInclusive}::as_str` methods tl;dr this allows viewing unyelded part of str-split-iterators, like so: ```rust let mut split = "Mary had a little lamb".split(' '); assert_eq!(split.as_str(), "Mary had a little lamb"); split.next(); assert_eq!(split.as_str(), "had a little lamb"); split.by_ref().for_each(drop); assert_eq!(split.as_str(), ""); ``` -------------- This PR adds semi-identical `as_str` methods to most str-split-iterators with signatures like `&'_ Split<'a, P: Pattern<'a>> -> &'a str` (Note: output `&str` lifetime is bound to the `'a`, not the `'_`). The methods are similar to [`Chars::as_str`] `SplitInclusive::as_str` is under `"str_split_inclusive_as_str"` feature gate, all other methods are under `"str_split_as_str"` feature gate. Before this PR you had to sum `len`s of all yielded parts or collect into `String` to emulate `as_str`. [`Chars::as_str`]: https://doc.rust-lang.org/core/str/struct.Chars.html#method.as_str
2 parents 075f2bf + 7bd6403 commit 977df43

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

library/core/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@
126126
#![feature(staged_api)]
127127
#![feature(std_internals)]
128128
#![feature(stmt_expr_attributes)]
129+
#![feature(str_split_as_str)]
130+
#![feature(str_split_inclusive_as_str)]
129131
#![feature(transparent_unions)]
130132
#![feature(unboxed_closures)]
131133
#![feature(unsized_locals)]

library/core/src/str/iter.rs

+164
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,17 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> {
690690
},
691691
}
692692
}
693+
694+
#[inline]
695+
fn as_str(&self) -> &'a str {
696+
// `Self::get_end` doesn't change `self.start`
697+
if self.finished {
698+
return "";
699+
}
700+
701+
// SAFETY: `self.start` and `self.end` always lie on unicode boundaries.
702+
unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }
703+
}
693704
}
694705

695706
generate_pattern_iterators! {
@@ -710,6 +721,48 @@ generate_pattern_iterators! {
710721
delegate double ended;
711722
}
712723

724+
impl<'a, P: Pattern<'a>> Split<'a, P> {
725+
/// Returns remainder of the splitted string
726+
///
727+
/// # Examples
728+
///
729+
/// ```
730+
/// #![feature(str_split_as_str)]
731+
/// let mut split = "Mary had a little lamb".split(' ');
732+
/// assert_eq!(split.as_str(), "Mary had a little lamb");
733+
/// split.next();
734+
/// assert_eq!(split.as_str(), "had a little lamb");
735+
/// split.by_ref().for_each(drop);
736+
/// assert_eq!(split.as_str(), "");
737+
/// ```
738+
#[inline]
739+
#[unstable(feature = "str_split_as_str", issue = "77998")]
740+
pub fn as_str(&self) -> &'a str {
741+
self.0.as_str()
742+
}
743+
}
744+
745+
impl<'a, P: Pattern<'a>> RSplit<'a, P> {
746+
/// Returns remainder of the splitted string
747+
///
748+
/// # Examples
749+
///
750+
/// ```
751+
/// #![feature(str_split_as_str)]
752+
/// let mut split = "Mary had a little lamb".rsplit(' ');
753+
/// assert_eq!(split.as_str(), "Mary had a little lamb");
754+
/// split.next();
755+
/// assert_eq!(split.as_str(), "Mary had a little");
756+
/// split.by_ref().for_each(drop);
757+
/// assert_eq!(split.as_str(), "");
758+
/// ```
759+
#[inline]
760+
#[unstable(feature = "str_split_as_str", issue = "77998")]
761+
pub fn as_str(&self) -> &'a str {
762+
self.0.as_str()
763+
}
764+
}
765+
713766
generate_pattern_iterators! {
714767
forward:
715768
/// Created with the method [`split_terminator`].
@@ -728,6 +781,48 @@ generate_pattern_iterators! {
728781
delegate double ended;
729782
}
730783

784+
impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> {
785+
/// Returns remainder of the splitted string
786+
///
787+
/// # Examples
788+
///
789+
/// ```
790+
/// #![feature(str_split_as_str)]
791+
/// let mut split = "A..B..".split_terminator('.');
792+
/// assert_eq!(split.as_str(), "A..B..");
793+
/// split.next();
794+
/// assert_eq!(split.as_str(), ".B..");
795+
/// split.by_ref().for_each(drop);
796+
/// assert_eq!(split.as_str(), "");
797+
/// ```
798+
#[inline]
799+
#[unstable(feature = "str_split_as_str", issue = "77998")]
800+
pub fn as_str(&self) -> &'a str {
801+
self.0.as_str()
802+
}
803+
}
804+
805+
impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> {
806+
/// Returns remainder of the splitted string
807+
///
808+
/// # Examples
809+
///
810+
/// ```
811+
/// #![feature(str_split_as_str)]
812+
/// let mut split = "A..B..".rsplit_terminator('.');
813+
/// assert_eq!(split.as_str(), "A..B..");
814+
/// split.next();
815+
/// assert_eq!(split.as_str(), "A..B");
816+
/// split.by_ref().for_each(drop);
817+
/// assert_eq!(split.as_str(), "");
818+
/// ```
819+
#[inline]
820+
#[unstable(feature = "str_split_as_str", issue = "77998")]
821+
pub fn as_str(&self) -> &'a str {
822+
self.0.as_str()
823+
}
824+
}
825+
731826
derive_pattern_clone! {
732827
clone SplitNInternal
733828
with |s| SplitNInternal { iter: s.iter.clone(), ..*s }
@@ -784,6 +879,11 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> {
784879
}
785880
}
786881
}
882+
883+
#[inline]
884+
fn as_str(&self) -> &'a str {
885+
self.iter.as_str()
886+
}
787887
}
788888

789889
generate_pattern_iterators! {
@@ -804,6 +904,48 @@ generate_pattern_iterators! {
804904
delegate single ended;
805905
}
806906

907+
impl<'a, P: Pattern<'a>> SplitN<'a, P> {
908+
/// Returns remainder of the splitted string
909+
///
910+
/// # Examples
911+
///
912+
/// ```
913+
/// #![feature(str_split_as_str)]
914+
/// let mut split = "Mary had a little lamb".splitn(3, ' ');
915+
/// assert_eq!(split.as_str(), "Mary had a little lamb");
916+
/// split.next();
917+
/// assert_eq!(split.as_str(), "had a little lamb");
918+
/// split.by_ref().for_each(drop);
919+
/// assert_eq!(split.as_str(), "");
920+
/// ```
921+
#[inline]
922+
#[unstable(feature = "str_split_as_str", issue = "77998")]
923+
pub fn as_str(&self) -> &'a str {
924+
self.0.as_str()
925+
}
926+
}
927+
928+
impl<'a, P: Pattern<'a>> RSplitN<'a, P> {
929+
/// Returns remainder of the splitted string
930+
///
931+
/// # Examples
932+
///
933+
/// ```
934+
/// #![feature(str_split_as_str)]
935+
/// let mut split = "Mary had a little lamb".rsplitn(3, ' ');
936+
/// assert_eq!(split.as_str(), "Mary had a little lamb");
937+
/// split.next();
938+
/// assert_eq!(split.as_str(), "Mary had a little");
939+
/// split.by_ref().for_each(drop);
940+
/// assert_eq!(split.as_str(), "");
941+
/// ```
942+
#[inline]
943+
#[unstable(feature = "str_split_as_str", issue = "77998")]
944+
pub fn as_str(&self) -> &'a str {
945+
self.0.as_str()
946+
}
947+
}
948+
807949
derive_pattern_clone! {
808950
clone MatchIndicesInternal
809951
with |s| MatchIndicesInternal(s.0.clone())
@@ -1134,6 +1276,28 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
11341276
#[unstable(feature = "split_inclusive", issue = "72360")]
11351277
impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
11361278

1279+
impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> {
1280+
/// Returns remainder of the splitted string
1281+
///
1282+
/// # Examples
1283+
///
1284+
/// ```
1285+
/// #![feature(str_split_inclusive_as_str)]
1286+
/// #![feature(split_inclusive)]
1287+
/// let mut split = "Mary had a little lamb".split_inclusive(' ');
1288+
/// assert_eq!(split.as_str(), "Mary had a little lamb");
1289+
/// split.next();
1290+
/// assert_eq!(split.as_str(), "had a little lamb");
1291+
/// split.by_ref().for_each(drop);
1292+
/// assert_eq!(split.as_str(), "");
1293+
/// ```
1294+
#[inline]
1295+
#[unstable(feature = "str_split_inclusive_as_str", issue = "77998")]
1296+
pub fn as_str(&self) -> &'a str {
1297+
self.0.as_str()
1298+
}
1299+
}
1300+
11371301
/// An iterator of [`u16`] over the string encoded as UTF-16.
11381302
///
11391303
/// This struct is created by the [`encode_utf16`] method on [`str`].

0 commit comments

Comments
 (0)