diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 315469387e5ae..60a55640667ca 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -133,6 +133,7 @@ #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] +#![feature(split_inclusive_variants)] #![feature(str_internals)] #![feature(strict_provenance)] #![feature(trusted_len)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 63d4d94529008..75138a7a16fa0 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -132,6 +132,13 @@ pub use core::slice::{Iter, IterMut}; pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; #[stable(feature = "slice_rsplit", since = "1.27.0")] pub use core::slice::{RSplit, RSplitMut}; +#[unstable(feature = "split_inclusive_variants", issue = "none")] +pub use core::slice::{ + RSplitInclusive, RSplitInclusiveMut, RSplitLeftInclusive, RSplitLeftInclusiveMut, + RSplitNInclusive, RSplitNInclusiveMut, RSplitNLeftInclusive, RSplitNLeftInclusiveMut, + SplitLeftInclusive, SplitLeftInclusiveMut, SplitNInclusive, SplitNInclusiveMut, + SplitNLeftInclusive, SplitNLeftInclusiveMut, +}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index d5ed2c4adf4f1..b44911e9947ff 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -67,6 +67,11 @@ pub use core::str::{MatchIndices, RMatchIndices}; pub use core::str::{Matches, RMatches}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplit, Split}; +#[unstable(feature = "split_inclusive_variants", issue = "none")] +pub use core::str::{ + RSplitInclusive, RSplitLeftInclusive, RSplitNInclusive, RSplitNLeftInclusive, SplitEnds, + SplitInitiator, SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive, +}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitN, SplitN}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index c29e7b9c81efb..53a39cc0a8986 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -42,6 +42,7 @@ #![feature(bench_black_box)] #![feature(strict_provenance)] #![feature(once_cell)] +#![feature(split_inclusive_variants)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 21f894343be09..f9b46cfc3ceb0 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -927,6 +927,246 @@ fn test_splitator_mut_inclusive_reverse() { assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); } +#[test] +fn test_splitator_left_inclusive() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_left_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_splitator_left_inclusive_reverse() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; + assert_eq!(xs.split_left_inclusive(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_left_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_splitator_left_inclusive_mut() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_left_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_splitator_left_inclusive_reverse_mut() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_left_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_rsplitator_inclusive() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(xs.rsplit_inclusive(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_rsplitator_inclusive_reverse() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_rsplitator_mut_inclusive() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_rsplitator_mut_inclusive_reverse() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_rsplitator_left_inclusive() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_left_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_rsplitator_left_inclusive_reverse() { + let xs = &[1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).rev().collect::>(), splits); +} + +#[test] +fn test_rsplitator_left_inclusive_mut() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x % 2 == 0).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).collect::>(), splits); +} + +#[test] +fn test_rsplitator_left_inclusive_reverse_mut() { + let xs = &mut [1, 2, 3, 4, 5]; + + let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x % 2 == 0).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); +} + #[test] fn test_splitnator() { let xs = &[1, 2, 3, 4, 5]; @@ -996,7 +1236,7 @@ fn test_rsplitnator() { #[test] fn test_split_iterators_size_hint() { - #[derive(Copy, Clone)] + #[derive(Copy, Clone, PartialEq, Eq)] enum Bounds { Lower, Upper, @@ -1027,8 +1267,9 @@ fn test_split_iterators_size_hint() { // p: predicate, b: bound selection for (p, b) in [ - // with a predicate always returning false, the split*-iterators - // become maximally short, so the size_hint lower bounds are tight + // with a predicate always returning false, the non-inclusive + // split*-iterators become maximally short, so the size_hint + // lower bounds are tight ((|_| false) as fn(&_) -> _, Bounds::Lower), // with a predicate always returning true, the split*-iterators // become maximally long, so the size_hint upper bounds are tight @@ -1039,8 +1280,10 @@ fn test_split_iterators_size_hint() { a(v.split(p), b, "split"); a(v.split_mut(p), b, "split_mut"); - a(v.split_inclusive(p), b, "split_inclusive"); - a(v.split_inclusive_mut(p), b, "split_inclusive_mut"); + if b == Bounds::Upper { + a(v.split_inclusive(p), b, "split_inclusive"); + a(v.split_inclusive_mut(p), b, "split_inclusive_mut"); + } a(v.rsplit(p), b, "rsplit"); a(v.rsplit_mut(p), b, "rsplit_mut"); diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 7379569dd68fe..28ff9aac722d2 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1438,6 +1438,63 @@ fn test_split_char_iterator_inclusive_rev() { assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]); } +#[test] +fn test_split_char_iterator_left_inclusive() { + let split: Vec<&str> = "\n\n\n\n".split_left_inclusive('\n').collect(); + assert_eq!(split, ["\n", "\n", "\n", "\n"]); + + let split: Vec<&str> = "".split_left_inclusive('\n').collect(); + let rhs: [&str; 0] = []; + assert_eq!(split, rhs); + + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split_left_inclusive('\n').collect(); + assert_eq!(split, ["\nMäry häd ä little lämb", "\nLittle lämb", "\n"]); + + let uppercase_separated = "SheePSharKTurtlECaT"; + let mut first_char = true; + let split: Vec<&str> = uppercase_separated + .split_left_inclusive(|c: char| { + let split = !first_char && c.is_uppercase(); + first_char = split; + split + }) + .collect(); + assert_eq!(split, ["Shee", "PShar", "KTurtl", "ECa", "T"]); +} + +#[test] +fn test_split_char_iterator_left_inclusive_rev() { + let split: Vec<&str> = "\n\n\n\n".split_left_inclusive('\n').rev().collect(); + assert_eq!(split, ["\n", "\n", "\n", "\n"]); + + let split: Vec<&str> = "".split_left_inclusive('\n').rev().collect(); + let rhs: [&str; 0] = []; + assert_eq!(split, rhs); + + let data = "\nMäry häd ä little lämb\nLittle lämb\n"; + + let split: Vec<&str> = data.split_left_inclusive('\n').rev().collect(); + assert_eq!(split, ["\n", "\nLittle lämb", "\nMäry häd ä little lämb"]); + + // Note that the predicate is stateful and thus dependent + // on the iteration order. + // (A different predicate is needed for reverse iterator vs normal iterator.) + // Not sure if anything can be done though. + let uppercase_separated = "SheePSharKTurtlECaT"; + let mut term_char = true; + let split: Vec<&str> = uppercase_separated + .split_left_inclusive(|c: char| { + let split = term_char && c.is_uppercase(); + term_char = c.is_uppercase(); + split + }) + .rev() + .collect(); + assert_eq!(split, ["T", "ECa", "KTurtl", "PShar", "Shee",]); +} + #[test] fn test_rsplit() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 35d00b9dda663..e6257711643ac 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -374,38 +374,36 @@ pub(super) trait SplitIter: DoubleEndedIterator { fn finish(&mut self) -> Option; } -/// An iterator over subslices separated by elements that match a predicate -/// function. -/// -/// This struct is created by the [`split`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 33, 20]; -/// let mut iter = slice.split(|num| num % 3 == 0); -/// ``` -/// -/// [`split`]: slice::split -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Split<'a, T: 'a, P> +split_iter! { + #[stable(feature = "rust1", since = "1.0.0")] + #[debug(stable(feature = "core_impl_debug", since = "1.9.0"))] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function. + /// + /// This struct is created by the [`split`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// ``` + /// + /// [`split`]: slice::split + /// [slices]: slice + struct Split { + include_leading: false, + include_trailing: false, + } +} + +impl<'a, T, P> Split<'a, T, P> where + T: 'a, P: FnMut(&T) -> bool, { - // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods - pub(crate) v: &'a [T], - pred: P, - // Used for `SplitAsciiWhitespace` `as_str` method - pub(crate) finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - Self { v: slice, pred, finished: false } - } /// Returns a slice which contains items not yet handled by split. /// # Example /// @@ -422,665 +420,276 @@ impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { } } -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Split<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Split<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - Split { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().position(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx + 1..]; - ret - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len() + 1` empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().rposition(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[idx + 1..]); - self.v = &self.v[..idx]; - ret - } - } - } -} - -impl<'a, T, P> SplitIter for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function. Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 33, 20]; -/// let mut iter = slice.split_inclusive(|num| num % 3 == 0); -/// ``` -/// -/// [`split_inclusive`]: slice::split_inclusive -/// [slices]: slice -#[stable(feature = "split_inclusive", since = "1.51.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitInclusive<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - let finished = slice.is_empty(); - Self { v: slice, pred, finished } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl fmt::Debug for SplitInclusive<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl Clone for SplitInclusive<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - let idx = - self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx..]; - ret - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len()` one-element slices, - // or a single empty slice. - (1, Some(cmp::max(1, self.v.len()))) - } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; - let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let ret = Some(&self.v[idx..]); - self.v = &self.v[..idx]; - ret - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. -/// -/// This struct is created by the [`split_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut v = [10, 40, 30, 20, 60, 50]; -/// let iter = v.split_mut(|num| *num % 3 == 0); -/// ``` -/// -/// [`split_mut`]: slice::split_mut -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - Self { v: slice, pred, finished: false } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -impl<'a, T, P> SplitIter for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = &mut tail[1..]; - Some(head) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len() + 1` empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().rposition(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(&mut tail[1..]) - } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched -/// parts in the ends of the subslices. -/// -/// This struct is created by the [`split_inclusive_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut v = [10, 40, 30, 20, 60, 50]; -/// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); -/// ``` -/// -/// [`split_inclusive_mut`]: slice::split_inclusive_mut -/// [slices]: slice -#[stable(feature = "split_inclusive", since = "1.51.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitInclusiveMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - let finished = slice.is_empty(); - Self { v: slice, pred, finished } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl fmt::Debug for SplitInclusiveMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusiveMut") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = tail; - Some(head) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len()` one-element slices, - // or a single empty slice. - (1, Some(cmp::max(1, self.v.len()))) - } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = if self.v.is_empty() { - None - } else { - // work around borrowck limitations - let pred = &mut self.pred; - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = &self.v[..(self.v.len() - 1)]; - remainder.iter().rposition(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(tail) - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [11, 22, 33, 0, 44, 55]; -/// let iter = slice.rsplit(|num| *num == 0); -/// ``` -/// -/// [`rsplit`]: slice::rsplit -/// [slices]: slice -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplit<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: Split<'a, T, P>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - Self { inner: Split::new(slice, pred) } - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplit<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplit") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl Clone for RSplit<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - RSplit { inner: self.inner.clone() } - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the subslices of the vector which are separated -/// by elements that match `pred`, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut slice = [11, 22, 33, 0, 44, 55]; -/// let iter = slice.rsplit_mut(|num| *num == 0); -/// ``` -/// -/// [`rsplit_mut`]: slice::rsplit_mut -/// [slices]: slice -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: SplitMut<'a, T, P>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - Self { inner: SplitMut::new(slice, pred) } +split_iter! { + #[stable(feature = "rust1", since = "1.0.0")] + #[debug(stable(feature = "core_impl_debug", since = "1.9.0"))] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`. + /// + /// This struct is created by the [`split_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.split_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`split_mut`]: slice::split_mut + /// [slices]: slice + struct SplitMut { + include_leading: false, + include_trailing: false, + } +} + +split_iter! { + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[debug(stable(feature = "core_impl_debug", since = "1.9.0"))] + #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function. Unlike `Split`, it contains the matched part as a terminator + /// of the subslice. + /// + /// This struct is created by the [`split_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`split_inclusive`]: slice::split_inclusive + /// [slices]: slice + struct SplitInclusive { + include_leading: false, + include_trailing: true, + } +} + +split_iter! { + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[debug(stable(feature = "split_inclusive", since = "1.51.0"))] + #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`. Unlike `SplitMut`, it contains the matched + /// parts in the ends of the subslices. + /// + /// This struct is created by the [`split_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`split_inclusive_mut`]: slice::split_inclusive_mut + /// [slices]: slice + struct SplitInclusiveMut { + include_leading: false, + include_trailing: true, + } +} + +split_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[debug(stable(feature = "split_inclusive", since = "1.51.0"))] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function. Unlike `Split`, it contains the matched part as an initiator + /// of the subslice. + /// + /// This struct is created by the [`split_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`split_left_inclusive`]: slice::split_left_inclusive + /// [slices]: slice + struct SplitLeftInclusive { + include_leading: true, + include_trailing: false, + } +} + +split_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[debug(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`. Unlike `SplitMut`, it contains the matched + /// parts in the beginnings of the subslices. + /// + /// This struct is created by the [`split_left_inclusive_mut`] method on + /// [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.split_left_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut + /// [slices]: slice + struct SplitLeftInclusiveMut { + include_leading: true, + include_trailing: false, } } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitMut") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } +reverse_iter! { + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, starting from the end of the slice. + /// + /// This struct is created by the [`rsplit`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let iter = slice.rsplit(|num| *num == 0); + /// ``` + /// + /// [`rsplit`]: slice::rsplit + /// [slices]: slice + pub struct RSplit { inner: Split }: Clone } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - self.inner.finish() - } +reverse_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order. Unlike `Split`, it contains the matched part as + /// an initiator of the subslice. + /// + /// This struct is created by the [`rsplit_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`rsplit_left_inclusive`]: slice::rsplit_inclusive + /// [slices]: slice + pub struct RSplitInclusive { inner: SplitInclusive }: Clone } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - self.inner.next_back() - } +reverse_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order. Unlike `Split`, it contains the matched part as + /// an initiator of the subslice. + /// + /// This struct is created by the [`rsplit_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_left_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`rsplit_left_inclusive`]: slice::rsplit_left_inclusive + /// [slices]: slice + pub struct RSplitLeftInclusive { inner: SplitLeftInclusive }: Clone +} - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } +reverse_iter! { + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the subslices of the vector which are separated + /// by elements that match `pred`, starting from the end of the slice. + /// + /// This struct is created by the [`rsplit_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut slice = [11, 22, 33, 0, 44, 55]; + /// let iter = slice.rsplit_mut(|num| *num == 0); + /// ``` + /// + /// [`rsplit_mut`]: slice::rsplit_mut + /// [slices]: slice + pub struct RSplitMut { inner: SplitMut } } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - self.inner.next() - } +reverse_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`, in reverse order. Unlike `SplitMut`, it + /// contains the matched parts in the ends of the subslices. + /// + /// This struct is created by the [`rsplit_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.rsplit_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`rsplit_inclusive_mut`]: slice::rsplit_inclusive_mut + /// [slices]: slice + pub struct RSplitInclusiveMut { inner: SplitInclusiveMut } } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} +reverse_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`, in reverse order. Unlike `SplitMut`, it + /// contains the matched parts in the beginnings of the subslices. + /// + /// This struct is created by the [`rsplit_left_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.rsplit_left_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`rsplit_left_inclusive_mut`]: slice::rsplit_left_inclusive_mut + /// [slices]: slice + pub struct RSplitLeftInclusiveMut { inner: SplitLeftInclusiveMut } +} /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. -#[derive(Debug)] +#[derive(Clone, Debug)] struct GenericSplitN { iter: I, count: usize, @@ -1114,172 +723,319 @@ impl> Iterator for GenericSplitN { } } -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.splitn(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`splitn`]: slice::splitn -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} +iter_n! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a given number of splits. + /// + /// This struct is created by the [`splitn`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.splitn(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`splitn`]: slice::splitn + /// [slices]: slice + pub struct SplitN { inner: Split }: Clone -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { - #[inline] - pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitN").field("inner", &self.inner).finish() - } +iter_n! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a + /// predicate function, limited to a given number of splits, starting + /// from the end of the slice. + /// + /// This struct is created by the [`rsplitn`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.rsplitn(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`rsplitn`]: slice::rsplitn + /// [slices]: slice + pub struct RSplitN { inner: RSplit }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`rsplitn`]: slice::rsplitn -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, +iter_n! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a given number of splits. + /// + /// This struct is created by the [`splitn_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`splitn_mut`]: slice::splitn_mut + /// [slices]: slice + pub struct SplitNMut { inner: SplitMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { - #[inline] - pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } +iter_n! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a + /// predicate function, limited to a given number of splits, starting + /// from the end of the slice. + /// + /// This struct is created by the [`rsplitn_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`rsplitn_mut`]: slice::rsplitn_mut + /// [slices]: slice + pub struct RSplitNMut { inner: RSplitMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitN").field("inner", &self.inner).finish() - } +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitN`, it + /// contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`splitn_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_inclusive`]: slice::splitn_inclusive + /// [slices]: slice + pub struct SplitNInclusive { inner: SplitInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`splitn_mut`]: slice::splitn_mut -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitN`, it + /// contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`splitn_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_left_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_left_inclusive`]: slice::splitn_left_inclusive + /// [slices]: slice + pub struct SplitNLeftInclusive { inner: SplitLeftInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { - #[inline] - pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`rsplitn_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_inclusive`]: slice::rsplitn_inclusive + /// [slices]: slice + pub struct RSplitNInclusive { inner: RSplitInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNMut").field("inner", &self.inner).finish() - } +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`rsplitn_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_left_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_left_inclusive`]: slice::rsplitn_left_inclusive + /// [slices]: slice + pub struct RSplitNLeftInclusive { inner: RSplitLeftInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`rsplitn_mut`]: slice::rsplitn_mut -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitNMut`, it + /// contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`splitn_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_inclusive_mut`]: slice::splitn_inclusive_mut + /// [slices]: slice + pub struct SplitNInclusiveMut { inner: SplitInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { - #[inline] - pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitNMut`, it + /// contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`splitn_left_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_left_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_left_inclusive_mut`]: slice::splitn_left_inclusive_mut + /// [slices]: slice + pub struct SplitNLeftInclusiveMut { inner: SplitLeftInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() - } +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`rsplitn_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_inclusive_mut`]: slice::rsplitn_inclusive_mut + /// [slices]: slice + pub struct RSplitNInclusiveMut { inner: RSplitInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } -forward_iterator! { SplitN: T, &'a [T] } -forward_iterator! { RSplitN: T, &'a [T] } -forward_iterator! { SplitNMut: T, &'a mut [T] } -forward_iterator! { RSplitNMut: T, &'a mut [T] } +iter_n! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`rsplitn_left_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_left_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_left_inclusive_mut`]: slice::rsplitn_left_inclusive_mut + /// [slices]: slice + pub struct RSplitNLeftInclusiveMut { inner: RSplitLeftInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; +} /// An iterator over overlapping subslices of length `size`. /// diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c05242222dde7..517a987198683 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -397,17 +397,414 @@ macro_rules! iterator { } } -macro_rules! forward_iterator { - ($name:ident: $elem:ident, $iter_of:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, $elem, P> Iterator for $name<'a, $elem, P> +macro_rules! split_iter { + ( + #[$stability:meta] + #[debug($debug_stability:meta)] + #[fused($fused_stability:meta)] + $(#[$outer:meta])* + struct $split_iter:ident< + $(shared_ref: & $lt:lifetime)? + $(mut_ref: & $m_lt:lifetime)? + > { + include_leading: $include_leading:literal, + include_trailing: $include_trailing:literal, + } + ) => { + $(#[$outer])* + #[$stability] + pub struct $split_iter<$($lt)? $($m_lt)?, T: $($lt)? $($m_lt)?, P> + where + P: FnMut(&T) -> bool, + { + // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods + pub(crate) v: &$($lt)?$($m_lt mut)? [T], + pred: P, + // Used for `SplitAsciiWhitespace` `as_str` method + pub(crate) finished: bool, + } + + impl<$($lt)?$($m_lt)?, T: $($lt)?$($m_lt)?, P: FnMut(&T) -> bool> $split_iter<$($lt)?$($m_lt)?, T, P> { + #[inline] + pub(super) fn new(slice: &$($lt)?$($m_lt mut)? [T], pred: P) -> Self { + Self { + v: slice, + pred, + finished: false, + } + } + } + + #[$debug_stability] + impl fmt::Debug for $split_iter<'_, T, P> + where + P: FnMut(&T) -> bool, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!(split_iter)) + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } + } + + split_iter! { + #[$stability] + impl Clone for $split_iter<$(shared_ref: &$lt)? $(mut_ref: &$m_lt)?> {} + } + + #[$stability] + impl<$($lt)?$($m_lt)?, T, P> Iterator for $split_iter<$($lt)?$($m_lt)?, T, P> + where + P: FnMut(&T) -> bool, + { + type Item = &$($lt)?$($m_lt mut)? [T]; + + #[inline] + fn next(&mut self) -> Option { + if self.finished { + return None; + } + + if $include_leading && self.v.is_empty() { + self.finished = true; + return None; + } + + let offset = if $include_leading { + // The first index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the right. + 1 + } else { + 0 + }; + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v[offset..].iter().position(|x| (*pred)(x)).map(|i| i + offset) + }; + + match idx_opt { + None => { + self.finished = true; + if $include_trailing && self.v.is_empty() { + return None; + } + $(let ret: & $lt [T] = self.v;)? + $(let ret: & $m_lt mut [T] = mem::replace(&mut self.v, &mut []);)? + Some(ret) + }, + Some(idx) => { + // For shared ref iters + $( + let ret_end = if $include_trailing { idx + 1 } else { idx }; + let ret: &$lt [T] = &self.v[..ret_end]; + let v_start = if $include_leading { idx } else { idx + 1 }; + self.v = &self.v[v_start..]; + Some(ret) + )? + + // For mut ref iters + $( + // Assert that include_leading and include_trailing are not both true + const _: [(); 0 - !{ const A: bool = !($include_leading && $include_trailing); A } as usize] = []; + let tmp: &$m_lt mut [T] = mem::replace(&mut self.v, &mut []); + let split_idx = if $include_trailing { idx + 1 } else { idx }; + let (head, tail) = tmp.split_at_mut(split_idx); + let tail_start = if ($include_leading ^ $include_trailing) { 0 } else { 1 }; + self.v = &mut tail[tail_start..]; + Some(head) + )? + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // If the predicate doesn't match anything, we yield one slice + // for exclusive iterators, and zero for inclusive ones. + // If it matches every element, we yield `len() + 1` empty slices. + let min = if $include_leading || $include_trailing { 0 } else { 1 }; + (min, Some(self.v.len() + min)) + } + } + } + + #[$stability] + impl<$($lt)?$($m_lt)?, T, P> DoubleEndedIterator for $split_iter<$($lt)?$($m_lt)?, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn next_back(&mut self) -> Option<::Item> { + if self.finished { + return None; + } + + if $include_trailing && self.v.is_empty() { + self.finished = true; + return None; + } + + let offset = if $include_trailing { + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + 1 + } else { + 0 + }; + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v[..(self.v.len() - offset)].iter().rposition(|x| (*pred)(x)) + }; + + match idx_opt { + None => { + self.finished = true; + if $include_leading && self.v.is_empty() { + return None; + } + $(let ret: & $lt [T] = self.v;)? + $(let ret: & $m_lt mut [T] = mem::replace(&mut self.v, &mut []);)? + Some(ret) + }, + Some(idx) => { + // For shared ref iters + $( + let ret_start = if $include_leading { idx } else { idx + 1 }; + let ret: &$lt [T] = &self.v[ret_start..]; + let v_end = if $include_trailing { idx + 1 } else { idx }; + self.v = &self.v[..v_end]; + Some(ret) + )? + + // For mut ref iters + $( + // Assert that include_leading and include_trailing are not both true + const _: [(); 0 - !{ const A: bool = !($include_leading && $include_trailing); A } as usize] = []; + let tmp: &$m_lt mut [T] = mem::replace(&mut self.v, &mut []); + let split_idx = if $include_trailing { idx + 1 } else { idx }; + let (head, tail) = tmp.split_at_mut(split_idx); + let tail_start = if ($include_leading ^ $include_trailing) { 0 } else { 1 }; + self.v = head; + let ret = &mut tail[tail_start..]; + Some(ret) + )? + } + } + } + } + + impl<$($lt)? $($m_lt)?, T, P> SplitIter for $split_iter<$($lt)? $($m_lt)?, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn finish(&mut self) -> Option<::Item> { + if self.finished { + None + } else { + self.finished = true; + $(let ret: & $lt [T] = self.v;)? + $(let ret: & $m_lt mut [T] = mem::replace(&mut self.v, &mut []);)? + if ($include_leading || $include_trailing) && ret.is_empty() { + None + } else { + Some(ret) + } + } + } + } + + #[$fused_stability] + impl FusedIterator for $split_iter<'_, T, P> where P: FnMut(&T) -> bool {} + }; + + ( + #[$stability:meta] + impl Clone for $split_iter:ident {} + ) => { + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` + #[$stability] + impl<$lt, T, P> Clone for $split_iter<$lt, T, P> + where + P: Clone + FnMut(&T) -> bool, + { + fn clone(&self) -> Self { + Self { + v: self.v, + pred: self.pred.clone(), + finished: self.finished + } + } + } + }; + + ( + #[$stability:meta] + impl Clone for $split_iter:ident {} + ) => {}; +} + +macro_rules! reverse_iter { + ( + #[$stability:meta] + $(#[$outer:meta])* + $vis:vis struct $rev:ident { inner: $inner:ident } $(: $clone:ident)? + ) => { + $(#[$outer])* + #[$stability] + $vis struct $rev<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - type Item = $iter_of; + inner: $inner<'a, T, P>, + } + impl<'a, T: 'a, P: FnMut(&T) -> bool> $rev<'a, T, P> { #[inline] - fn next(&mut self) -> Option<$iter_of> { + pub(super) fn new(slice: <$inner<'a, T, P> as Iterator>::Item, pred: P) -> Self { + Self { inner: $inner::new(slice, pred) } + } + } + + #[$stability] + impl fmt::Debug for $rev<'_, T, P> + where + P: FnMut(&T) -> bool, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($rev)) + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } + } + + $( + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` + #[$stability] + impl<'a, T, P> $clone for $rev<'a, T, P> + where + P: Clone + FnMut(&T) -> bool, + { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } + } + )? + + #[$stability] + impl<'a, T, P> Iterator for $rev<'a, T, P> + where + P: FnMut(&T) -> bool, + { + type Item = <$inner<'a, T, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + #[$stability] + impl<'a, T, P> DoubleEndedIterator for $rev<'a, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.next() + } + } + + #[$stability] + impl FusedIterator for $rev<'_, T, P> where P: FnMut(&T) -> bool {} + + #[$stability] + impl<'a, T, P> SplitIter for $rev<'a, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn finish(&mut self) -> Option { + self.inner.finish() + } + } + }; +} + +#[allow(unused)] +macro_rules! iter_n { + ( + #[$stability:meta] + #[fused($fused_stability:meta)] + $(#[$outer:meta])* + $vis:vis struct $iter_n:ident { inner: $inner:ident } $(: $clone:ident)? + + $(#[$max_items_attrs:meta])* + fn max_items; + ) => { + $(#[$outer])* + #[$stability] + pub struct $iter_n<'a, T: 'a, P> + where + P: FnMut(&T) -> bool, + { + inner: GenericSplitN<$inner<'a, T, P>>, + } + + impl<'a, T: 'a, P: FnMut(&T) -> bool> $iter_n<'a, T, P> { + #[inline] + pub(super) fn new(s: $inner<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } + } + + $( + #[$stability] + impl<'a, T: 'a, P> $clone for $iter_n<'a, T, P> + where + P: Clone + FnMut(&T) -> bool, + { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } + } + )? + + #[$stability] + impl fmt::Debug for $iter_n<'_, T, P> + where + P: FnMut(&T) -> bool, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($iter_n)).field("inner", &self.inner).finish() + } + } + + #[$stability] + impl<'a, T, P> Iterator for $iter_n<'a, T, P> + where + P: FnMut(&T) -> bool, + { + type Item = <$inner<'a, T, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } @@ -417,7 +814,15 @@ macro_rules! forward_iterator { } } - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} + #[$fused_stability] + impl<'a, T, P> FusedIterator for $iter_n<'a, T, P> where P: FnMut(&T) -> bool {} + + impl<'a, T, P> $inner<'a, T, P> where P: FnMut(&T) -> bool { + $(#[$max_items_attrs])* + #[inline] + pub fn max_items(self, n: usize) -> $iter_n<'a, T, P> { + $iter_n::new(self, n) + } + } }; } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 77fd1ec2b8ea2..5c65f4c71bd27 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -65,6 +65,14 @@ pub use iter::{GroupBy, GroupByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[unstable(feature = "split_inclusive_variants", issue = "none")] +pub use iter::{ + RSplitInclusive, RSplitInclusiveMut, RSplitLeftInclusive, RSplitLeftInclusiveMut, + RSplitNInclusive, RSplitNInclusiveMut, RSplitNLeftInclusive, RSplitNLeftInclusiveMut, + SplitLeftInclusive, SplitLeftInclusiveMut, SplitNInclusive, SplitNInclusiveMut, + SplitNLeftInclusive, SplitNLeftInclusiveMut, +}; + #[stable(feature = "rust1", since = "1.0.0")] pub use raw::{from_raw_parts, from_raw_parts_mut}; @@ -1909,6 +1917,68 @@ impl [T] { SplitMut::new(self, pred) } + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplit::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitMut::new(self, pred) + } + /// Returns an iterator over subslices separated by elements that match /// `pred`. The matched element is contained in the end of the previous /// subslice as a terminator. @@ -1952,6 +2022,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(split_inclusive_variants)] + /// /// let mut v = [10, 40, 30, 20, 60, 50]; /// /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { @@ -1970,65 +2042,199 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, starting at the end of the slice and working backwards. - /// The matched element is not contained in the subslices. + /// `pred`, in reverse order. The matched element is contained in the end + /// of the previous subslice as a terminator. /// /// # Examples /// /// ``` - /// let slice = [11, 22, 33, 0, 44, 55]; - /// let mut iter = slice.rsplit(|num| *num == 0); + /// #![feature(split_inclusive_variants)] /// - /// assert_eq!(iter.next().unwrap(), &[44, 55]); - /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); - /// assert_eq!(iter.next(), None); + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert!(iter.next().is_none()); /// ``` /// - /// As with `split()`, if the first or last element is matched, an empty - /// slice will be the first (or last) item returned by the iterator. + /// If the last element of the slice is matched, + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the first item returned by the iterator. /// /// ``` - /// let v = &[0, 1, 1, 2, 3, 5, 8]; - /// let mut it = v.rsplit(|n| *n % 2 == 0); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next().unwrap(), &[3, 5]); - /// assert_eq!(it.next().unwrap(), &[1, 1]); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next(), None); + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert!(iter.next().is_none()); /// ``` - #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + pub fn rsplit_inclusive(&self, pred: F) -> RSplitInclusive<'_, T, F> where F: FnMut(&T) -> bool, { - RSplit::new(self, pred) + RSplitInclusive::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`, starting at the end of the slice and working - /// backwards. The matched element is not contained in the subslices. + /// match `pred`, in reverse order. The matched element is contained in the + /// previous subslice as a terminator. /// /// # Examples /// /// ``` - /// let mut v = [100, 400, 300, 200, 600, 500]; + /// #![feature(split_inclusive_variants)] /// - /// let mut count = 0; - /// for group in v.rsplit_mut(|num| *num % 3 == 0) { - /// count += 1; - /// group[0] = count; + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; /// } - /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_inclusive_mut(&mut self, pred: F) -> RSplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the start of the following + /// subslice as an initiator. /// - #[stable(feature = "slice_rsplit", since = "1.27.0")] + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the initiator of a new slice. + /// That slice will be the last item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[3, 10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + pub fn split_left_inclusive(&self, pred: F) -> SplitLeftInclusive<'_, T, F> where F: FnMut(&T) -> bool, { - RSplitMut::new(self, pred) + SplitLeftInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the following + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_left_inclusive_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_left_inclusive_mut(&mut self, pred: F) -> SplitLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitLeftInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order. The matched element is contained in the start + /// of the following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the initiator of a new slice. + /// That slice will be the first item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.rsplit_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[33]); + /// assert_eq!(iter.next().unwrap(), &[3, 10, 40]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_left_inclusive(&self, pred: F) -> RSplitLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitLeftInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplit_left_inclusive_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_left_inclusive_mut(&mut self, pred: F) -> RSplitLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitLeftInclusiveMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -2056,7 +2262,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitN::new(self.split(pred), n) + self.split(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2082,7 +2288,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNMut::new(self.split_mut(pred), n) + self.split_mut(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2111,7 +2317,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitN::new(self.rsplit(pred), n) + self.rsplit(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2138,7 +2344,221 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNMut::new(self.rsplit_mut(pred), n) + self.rsplit_mut(pred).max_items(n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the end of the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20, 30]; + /// let mut iter = slice.splitn_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[20, 30]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_inclusive(&self, n: usize, pred: F) -> SplitNInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + self.split_inclusive(pred).max_items(n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_inclusive_mut(2, |num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 60, 1]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_inclusive_mut(&mut self, n: usize, pred: F) -> SplitNInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + self.split_inclusive_mut(pred).max_items(n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order, limited to returning at most `n` items. The + /// matched element is contained in the end of the previous subslice as a + /// terminator. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [20, 60, 10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert_eq!(iter.next().unwrap(), &[20, 60, 10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_inclusive(&self, n: usize, pred: F) -> RSplitNInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + self.rsplit_inclusive(pred).max_items(n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// previous subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn_inclusive_mut(2, |num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 30, 20, 1, 1]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_inclusive_mut(&mut self, n: usize, pred: F) -> RSplitNInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + self.rsplit_inclusive_mut(pred).max_items(n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the start of the following + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20, 9]; + /// let mut iter = slice.splitn_left_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33, 20, 9]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_left_inclusive(&self, n: usize, pred: F) -> SplitNLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNLeftInclusive::new(self.split_left_inclusive(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the following + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50, 90]; + /// + /// for group in v.splitn_left_inclusive_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 1, 20, 60, 50, 90]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_left_inclusive_mut( + &mut self, + n: usize, + pred: F, + ) -> SplitNLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNLeftInclusiveMut::new(self.split_left_inclusive_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order. The matched element is contained in the start + /// of the following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 9, 10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_left_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert_eq!(iter.next().unwrap(), &[3, 9, 10, 40]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_left_inclusive(&self, n: usize, pred: F) -> RSplitNLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNLeftInclusive::new(self.rsplit_left_inclusive(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn_left_inclusive_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 20, 1, 50]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_left_inclusive_mut( + &mut self, + n: usize, + pred: F, + ) -> RSplitNLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNLeftInclusiveMut::new(self.rsplit_left_inclusive_mut(pred), n) } /// Returns `true` if the slice contains an element with the given value. diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 24083ee6af44f..a40e990b39fc4 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -358,11 +358,19 @@ unsafe impl TrustedRandomAccessNoCoerce for Bytes<'_> { /// This macro generates a Clone impl for string pattern API /// wrapper types of the form X<'a, P> macro_rules! derive_pattern_clone { - (clone $t:ident with |$s:ident| $e:expr) => { + ( + $(#[$impl_attr:meta])* + clone $t:ident + $(where Searcher: ($where_clause:path))? + with $(#[$fn_attr:meta])* |$s:ident| $e:expr + ) => { + $(#[$impl_attr])* impl<'a, P> Clone for $t<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern<'a, Searcher: $($where_clause +)? Clone>, { + $(#[$fn_attr])* + #[inline] fn clone(&self) -> Self { let $s = self; $e @@ -409,21 +417,27 @@ macro_rules! derive_pattern_clone { /// so the two wrapper structs implement `Iterator` /// and `DoubleEndedIterator` depending on the concrete pattern type, leading /// to the complex impls seen above. +/// +/// In addition, when requested, as_str methods are are also generated for all iterators. macro_rules! generate_pattern_iterators { { // Forward iterator forward: + #[$forward_stability_attribute:meta] + #[fused($forward_fused_stability_attribute:meta)] $(#[$forward_iterator_attribute:meta])* struct $forward_iterator:ident; + $($(#[$forward_as_str_attribute:meta])* + fn as_str;)? // Reverse iterator reverse: + #[$reverse_stability_attribute:meta] + #[fused($reverse_fused_stability_attribute:meta)] $(#[$reverse_iterator_attribute:meta])* struct $reverse_iterator:ident; - - // Stability of all generated items - stability: - $(#[$common_stability_attribute:meta])* + $($(#[$reverse_as_str_attribute:meta])* + fn as_str;)? // Internal almost-iterator that is being delegated to internal: @@ -433,10 +447,16 @@ macro_rules! generate_pattern_iterators { delegate $($t:tt)* } => { $(#[$forward_iterator_attribute])* - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] + #[repr(transparent)] pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); - $(#[$common_stability_attribute])* + derive_pattern_clone! { + #[$forward_stability_attribute] + clone $forward_iterator with |s| Self(s.0.clone()) + } + + #[$forward_stability_attribute] impl<'a, P> fmt::Debug for $forward_iterator<'a, P> where P: Pattern<'a, Searcher: fmt::Debug>, @@ -448,34 +468,41 @@ macro_rules! generate_pattern_iterators { } } - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { type Item = $iterty; #[inline] - fn next(&mut self) -> Option<$iterty> { + fn next(&mut self) -> Option { self.0.next() } } - $(#[$common_stability_attribute])* - impl<'a, P> Clone for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - $forward_iterator(self.0.clone()) + $(impl<'a, P: Pattern<'a>> $forward_iterator<'a, P> { + $(#[$forward_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.0.as_str() } - } + })? + + #[$forward_fused_stability_attribute] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} $(#[$reverse_iterator_attribute])* - $(#[$common_stability_attribute])* - pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + #[$reverse_stability_attribute] + #[repr(transparent)] + pub struct $reverse_iterator<'a, P>(pub(super) $internal_iterator<'a, P>) where P: Pattern<'a, Searcher: ReverseSearcher<'a>>; + + derive_pattern_clone! { + #[$reverse_stability_attribute] + clone $reverse_iterator where Searcher: (ReverseSearcher<'a>) with |s| Self(s.0.clone()) + } - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern<'a, Searcher: ReverseSearcher<'a> + fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($reverse_iterator)) @@ -484,7 +511,7 @@ macro_rules! generate_pattern_iterators { } } - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> Iterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, @@ -492,484 +519,893 @@ macro_rules! generate_pattern_iterators { type Item = $iterty; #[inline] - fn next(&mut self) -> Option<$iterty> { + fn next(&mut self) -> Option { self.0.next_back() } } - $(#[$common_stability_attribute])* - impl<'a, P> Clone for $reverse_iterator<'a, P> + $(impl<'a, P> $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - fn clone(&self) -> Self { - $reverse_iterator(self.0.clone()) + $(#[$reverse_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.0.as_str() } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + })? - #[stable(feature = "fused", since = "1.26.0")] + #[$reverse_fused_stability_attribute] impl<'a, P> FusedIterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, {} - generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, - $forward_iterator, - $reverse_iterator, $iterty); + generate_pattern_iterators!($($t)* with + #[$forward_stability_attribute] + $forward_iterator, + #[$reverse_stability_attribute] + $reverse_iterator, + yielding $iterty + ); }; { - double ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty + double ended; with + #[$forward_stability_attribute:meta] + $forward_iterator:ident, + #[$reverse_stability_attribute:meta] + $reverse_iterator:ident, + yielding $iterty:ty } => { - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> where P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { #[inline] - fn next_back(&mut self) -> Option<$iterty> { + fn next_back(&mut self) -> Option<::Item> { self.0.next_back() } } - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { #[inline] - fn next_back(&mut self) -> Option<$iterty> { + fn next_back(&mut self) -> Option<::Item> { self.0.next() } } }; { - single ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty + single ended; with + #[$forward_stability_attribute:meta] + $forward_iterator:ident, + #[$reverse_stability_attribute:meta] + $reverse_iterator:ident, + yielding $iterty:ty } => {} } -derive_pattern_clone! { - clone SplitInternal - with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } -} +trait SplitIterInternal<'a>: Sized { + type Pat: Pattern<'a>; + fn next(&mut self) -> Option<&'a str>; -pub(super) struct SplitInternal<'a, P: Pattern<'a>> { - pub(super) start: usize, - pub(super) end: usize, - pub(super) matcher: P::Searcher, - pub(super) allow_trailing_empty: bool, - pub(super) finished: bool, -} + fn next_back(&mut self) -> Option<&'a str> + where + <>::Pat as Pattern<'a>>::Searcher: ReverseSearcher<'a>; -impl<'a, P> fmt::Debug for SplitInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInternal") - .field("start", &self.start) - .field("end", &self.end) - .field("matcher", &self.matcher) - .field("allow_trailing_empty", &self.allow_trailing_empty) - .field("finished", &self.finished) - .finish() - } + fn finish(&mut self) -> Option<&'a str>; + + fn as_str(&self) -> &'a str; } -impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { - #[inline] - fn get_end(&mut self) -> Option<&'a str> { - if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { - self.finished = true; - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { - let string = self.matcher.haystack().get_unchecked(self.start..self.end); - Some(string) +macro_rules! split_internal { + ( + $split_struct:ident { + $(skip_leading_empty: $skip_leading_empty:ident,)? + $(skip_trailing_empty: $skip_trailing_empty:ident,)? + include_leading: $include_leading:literal, + include_trailing: $include_trailing:literal, + } + ) => { + pub(super) struct $split_struct<'a, P: Pattern<'a>> { + pub(super) start: usize, + pub(super) end: usize, + pub(super) matcher: P::Searcher, + pub(super) finished: bool, + $(pub(super) $skip_leading_empty: bool,)? + $(pub(super) $skip_trailing_empty: bool,)? + } + + derive_pattern_clone! { + clone $split_struct + with |s| $split_struct { matcher: s.matcher.clone(), ..*s } + } + + impl<'a, P> fmt::Debug for $split_struct<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!(split_struct)) + .field("start", &self.start) + .field("end", &self.end) + .field("matcher", &self.matcher) + .field("finished", &self.finished) + $(.field("skip_leading_empty", &self.$skip_leading_empty))? + $(.field("skip_trailing_empty", &self.$skip_trailing_empty))? + .finish() } - } else { - None } - } - #[inline] - fn next(&mut self) -> Option<&'a str> { - if self.finished { - return None; + impl<'a, P: Pattern<'a>> $split_struct<'a, P> { + #[inline] + pub(super) fn new(s: &'a str, pat: P) -> Self { + $split_struct { + start: 0, + end: s.len(), + matcher: pat.into_searcher(s), + finished: false, + $($skip_leading_empty: true,)? + $($skip_trailing_empty: true,)? + } + } } - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..a); - self.start = b; - Some(elt) - }, - None => self.get_end(), + impl<'a, P: Pattern<'a>> SplitIterInternal<'a> for $split_struct<'a, P> { + type Pat = P; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } + + $(if self.$skip_leading_empty { + self.$skip_leading_empty = false; + match self.next() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + })? + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let end_idx = if $include_trailing { b } else { a }; + let elt = haystack.get_unchecked(self.start..end_idx); + self.start = if $include_leading { a } else { b }; + Some(elt) + }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + None => unsafe { + let end = haystack.get_unchecked(self.start..self.end); + self.finished = true; + $(if self.$skip_trailing_empty && end == "" { return None; })? + Some(end) + }, + } + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } + + $(if self.$skip_trailing_empty { + self.$skip_trailing_empty = false; + match self.next_back() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + })? + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let start_idx = if $include_leading { a } else { b }; + let elt = haystack.get_unchecked(start_idx..self.end); + self.end = if $include_trailing { b } else { a }; + Some(elt) + }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + None => unsafe { + let end = haystack.get_unchecked(self.start..self.end); + self.finished = true; + $(if self.$skip_leading_empty && end == "" { return None; })? + Some(end) + }, + } + } + + #[inline] + fn finish(&mut self) -> Option<&'a str> { + if self.finished { + None + } else { + self.finished = true; + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + let end = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }; + if (false + $(|| self.$skip_leading_empty)? + $(|| self.$skip_trailing_empty)? + ) && end == "" { + None + } else { + Some(end) + } + } + } + + #[inline] + fn as_str(&self) -> &'a str { + // `Self::finish` doesn't change `self.start` + if self.finished { + "" + } else { + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } + } + } } } +} - #[inline] - fn next_inclusive(&mut self) -> Option<&'a str> { - if self.finished { - return None; +macro_rules! generate_n_iterators { + ( + forward: + #[$forward_stability_attribute:meta] + #[fused($forward_fused_stability_attribute:meta)] + $(#[$forward_iterator_attribute:meta])* + struct $forward_n_iterator:ident { inner: $forward_inner_iterator:ident } + + $(#[$forward_max_items_attribute:meta])* + fn max_items; + + $($(#[$forward_as_str_attribute:meta])* + fn as_str;)? + reverse: + #[$reverse_stability_attribute:meta] + #[fused($reverse_fused_stability_attribute:meta)] + $(#[$reverse_iterator_attribute:meta])* + struct $reverse_n_iterator:ident { inner: $reverse_inner_iterator:ident } + + $(#[$reverse_max_items_attribute:meta])* + fn max_items; + + $($(#[$reverse_as_str_attribute:meta])* + fn as_str;)? + ) => { + #[$forward_stability_attribute] + $(#[$forward_iterator_attribute])* + pub struct $forward_n_iterator<'a, P: Pattern<'a>> { + iter: $forward_inner_iterator<'a, P>, + count: usize } - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.start is either the start of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..b); - self.start = b; - Some(elt) - }, - None => self.get_end(), + derive_pattern_clone! { + #[$forward_stability_attribute] + clone $forward_n_iterator with |s| Self { iter: s.iter.clone(), count: s.count } } - } - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; + #[$forward_stability_attribute] + impl<'a, P> fmt::Debug for $forward_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($forward_n_iterator)) + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } } - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; - match self.next_back() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; + #[$forward_stability_attribute] + impl<'a, P: Pattern<'a>> Iterator for $forward_n_iterator<'a, P> { + type Item = <$forward_inner_iterator<'a, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.0.finish() + } + _ => { + self.count -= 1; + self.iter.next() } } } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.count)) + } } - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = a; - Some(elt) - }, - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, + $(impl<'a, P: Pattern<'a>> $forward_n_iterator<'a, P> { + $(#[$forward_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.iter.as_str() + } + })? + + impl<'a, P: Pattern<'a>> $forward_inner_iterator<'a, P> { + $(#[$forward_max_items_attribute])* + #[inline] + pub fn max_items(self, n: usize) -> $forward_n_iterator<'a, P> { + $forward_n_iterator { iter: self, count: n } + } } - } - #[inline] - fn next_back_inclusive(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; + #[$forward_fused_stability_attribute] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_n_iterator<'a, P> {} + + #[$reverse_stability_attribute] + $(#[$reverse_iterator_attribute])* + pub struct $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + iter: $reverse_inner_iterator<'a, P>, + count: usize + } + + derive_pattern_clone! { + #[$reverse_stability_attribute] + clone $reverse_n_iterator where Searcher: (ReverseSearcher<'a>) with |s| Self { iter: s.iter.clone(), count: s.count } + } + + #[$reverse_stability_attribute] + impl<'a, P> fmt::Debug for $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a> + fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($reverse_n_iterator)) + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } } - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; - match self.next_back_inclusive() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; + #[$reverse_stability_attribute] + impl<'a, P> Iterator for $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + type Item = <$reverse_inner_iterator<'a, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.0.finish() + } + _ => { + self.count -= 1; + self.iter.next() } } } - } - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = b; - Some(elt) - }, - // SAFETY: self.start is either the start of the original string, - // or start of a substring that represents the part of the string that hasn't - // iterated yet. Either way, it is guaranteed to lie on unicode boundary. - // self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.count)) + } } - } - #[inline] - fn as_str(&self) -> &'a str { - // `Self::get_end` doesn't change `self.start` - if self.finished { - return ""; + $(impl<'a, P> $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + $(#[$reverse_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.iter.as_str() + } + })? + + + impl<'a, P> $reverse_inner_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + $(#[$reverse_max_items_attribute])* + #[inline] + pub fn max_items(self, n: usize) -> $reverse_n_iterator<'a, P> { + $reverse_n_iterator { iter: self, count: n } + } } - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } + #[$reverse_fused_stability_attribute] + impl<'a, P> FusedIterator for $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + {} + } +} + +split_internal! { + SplitInternal { + include_leading: false, + include_trailing: false, } } generate_pattern_iterators! { forward: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`split`]. /// /// [`split`]: str::split struct Split; + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// 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(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + reverse: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rsplit`]. /// /// [`rsplit`]: str::rsplit struct RSplit; - stability: - #[stable(feature = "rust1", since = "1.0.0")] + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplit(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + internal: SplitInternal yielding (&'a str); delegate double ended; } -impl<'a, P: Pattern<'a>> Split<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// 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(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } +generate_n_iterators! { + forward: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + /// Created with the method [`splitn`]. + /// + /// [`splitn`]: str::splitn + struct SplitN { inner: Split } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + + reverse: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + /// Created with the method [`rsplitn`]. + /// + /// [`rsplitn`]: str::rsplitn + struct RSplitN { inner: RSplit } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; } -impl<'a, P: Pattern<'a>> RSplit<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".rsplit(' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "Mary had a little"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() +split_internal! { + SplitInclusiveInternal { + skip_trailing_empty: skip_trailing_empty, + include_leading: false, + include_trailing: true, } } generate_pattern_iterators! { forward: - /// Created with the method [`split_terminator`]. + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] + /// Created with the method [`split_inclusive`]. /// - /// [`split_terminator`]: str::split_terminator - struct SplitTerminator; + /// [`split_inclusive`]: str::split_inclusive + struct SplitInclusive; + + /// Returns remainder of the split string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// let mut split = "Mary had a little lamb".split_inclusive(' '); + /// 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(), ""); + /// ``` + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + reverse: - /// Created with the method [`rsplit_terminator`]. + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_inclusive`]. /// - /// [`rsplit_terminator`]: str::rsplit_terminator - struct RSplitTerminator; - stability: - #[stable(feature = "rust1", since = "1.0.0")] + /// [`rsplit_inclusive`]: str::rsplit_inclusive + struct RSplitInclusive; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + internal: - SplitInternal yielding (&'a str); + SplitInclusiveInternal yielding (&'a str); delegate double ended; } -impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "A..B..".split_terminator('.'); - /// assert_eq!(split.as_str(), "A..B.."); - /// split.next(); - /// assert_eq!(split.as_str(), ".B.."); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`splitn_inclusive`]. + /// + /// [`splitn_inclusive`]: str::splitn_inclusive + struct SplitNInclusive { inner: SplitInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplitn_inclusive`]. + /// + /// [`rsplitn_inclusive`]: str::rsplitn_inclusive + struct RSplitNInclusive { inner: RSplitInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; } -impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "A..B..".rsplit_terminator('.'); - /// assert_eq!(split.as_str(), "A..B.."); - /// split.next(); - /// assert_eq!(split.as_str(), "A..B"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() +split_internal! { + SplitLeftInclusiveInternal { + skip_leading_empty: skip_leading_empty, + include_leading: true, + include_trailing: false, } } -derive_pattern_clone! { - clone SplitNInternal - with |s| SplitNInternal { iter: s.iter.clone(), ..*s } +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`split_left_inclusive`]. + /// + /// [`split_left_inclusive`]: str::split_left_inclusive + struct SplitLeftInclusive; + + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// #![feature(split_inclusive_variants)] + /// let mut split = "Mary had a little lamb".split_left_inclusive(' '); + /// 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(), ""); + /// ``` + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_left_inclusive`]. + /// + /// [`rsplit_left_inclusive`]: str::rsplit_left_inclusive + struct RSplitLeftInclusive; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + internal: + SplitLeftInclusiveInternal yielding (&'a str); + delegate double ended; } -pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { - pub(super) iter: SplitInternal<'a, P>, - /// The number of splits remaining - pub(super) count: usize, +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`splitn_left_inclusive`]. + /// + /// [`splitn_left_inclusive`]: str::splitn_left_inclusive + struct SplitNLeftInclusive { inner: SplitLeftInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplitn_left_inclusive`]. + /// + /// [`rsplitn_left_inclusive`]: str::rsplitn_left_inclusive + struct RSplitNLeftInclusive { inner: RSplitLeftInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; } -impl<'a, P> fmt::Debug for SplitNInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNInternal") - .field("iter", &self.iter) - .field("count", &self.count) - .finish() +split_internal! { + SplitInitiatorInternal { + skip_leading_empty: skip_leading_empty, + include_leading: false, + include_trailing: false, } } -impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`split_initiator`]. + /// + /// [`split_initiator`]: str::split_initiator + struct SplitInitiator; - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next_back() - } - } - } + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; - #[inline] - fn as_str(&self) -> &'a str { - self.iter.as_str() + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_initiator`]. + /// + /// [`rsplit_initiator`]: str::rsplit_initiator + struct RSplitInitiator; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + + internal: + SplitInitiatorInternal yielding (&'a str); + delegate double ended; +} + +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct SplitNInitiator { inner: SplitInitiator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct RSplitNInitiator { inner: RSplitInitiator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; +} + +split_internal! { + SplitTerminatorInternal { + skip_trailing_empty: skip_trailing_empty, + include_leading: false, + include_trailing: false, } } generate_pattern_iterators! { forward: - /// Created with the method [`splitn`]. + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + /// Created with the method [`split_terminator`]. /// - /// [`splitn`]: str::splitn - struct SplitN; - reverse: - /// Created with the method [`rsplitn`]. + /// [`split_terminator`]: str::split_terminator + struct SplitTerminator; + + /// Returns remainder of the split string. /// - /// [`rsplitn`]: str::rsplitn - struct RSplitN; - stability: + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".split_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), ".B.."); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + + reverse: #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + /// Created with the method [`rsplit_terminator`]. + /// + /// [`rsplit_terminator`]: str::rsplit_terminator + struct RSplitTerminator; + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".rsplit_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), "A..B"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + internal: - SplitNInternal yielding (&'a str); - delegate single ended; + SplitTerminatorInternal yielding (&'a str); + delegate double ended; } -impl<'a, P: Pattern<'a>> SplitN<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".splitn(3, ' '); - /// 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(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct SplitNTerminator { inner: SplitTerminator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct RSplitNTerminator { inner: RSplitTerminator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; } -impl<'a, P: Pattern<'a>> RSplitN<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".rsplitn(3, ' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "Mary had a little"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() +split_internal! { + SplitEndsInternal { + skip_leading_empty: skip_leading_empty, + skip_trailing_empty: skip_trailing_empty, + include_leading: false, + include_trailing: false, } } +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`split_ends`]. + /// + /// [`split_ends`]: str::split_ends + struct SplitEnds; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_ends`]. + /// + /// [`rsplit_ends`]: str::rsplit_ends + struct RSplitEnds; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + + internal: + SplitEndsInternal yielding (&'a str); + delegate double ended; +} + +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct SplitNEnds { inner: SplitEnds } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct RSplitNEnds { inner: RSplitEnds } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; +} + derive_pattern_clone! { clone MatchIndicesInternal with |s| MatchIndicesInternal(s.0.clone()) @@ -1009,17 +1445,19 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`match_indices`]. /// /// [`match_indices`]: str::match_indices struct MatchIndices; reverse: + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rmatch_indices`]. /// /// [`rmatch_indices`]: str::rmatch_indices struct RMatchIndices; - stability: - #[stable(feature = "str_match_indices", since = "1.5.0")] internal: MatchIndicesInternal yielding ((usize, &'a str)); delegate double ended; @@ -1066,17 +1504,19 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: + #[stable(feature = "str_matches", since = "1.2.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`matches`]. /// /// [`matches`]: str::matches struct Matches; reverse: + #[stable(feature = "str_matches", since = "1.2.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rmatches`]. /// /// [`rmatches`]: str::rmatches struct RMatches; - stability: - #[stable(feature = "str_matches", since = "1.2.0")] internal: MatchesInternal yielding (&'a str); delegate double ended; @@ -1190,18 +1630,6 @@ pub struct SplitAsciiWhitespace<'a> { Map, BytesIsNotEmpty>, UnsafeBytesToStr>, } -/// An iterator over the substrings of a string, -/// terminated by a substring matching to a predicate function -/// Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_inclusive`]: str::split_inclusive -#[stable(feature = "split_inclusive", since = "1.51.0")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); - #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; @@ -1319,65 +1747,6 @@ impl<'a> SplitAsciiWhitespace<'a> { } } -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next_inclusive() - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive").field("0", &self.0).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { - fn clone(&self) -> Self { - SplitInclusive(self.0.clone()) - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator - for SplitInclusive<'a, P> -{ - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back_inclusive() - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} - -impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_inclusive_as_str)] - /// let mut split = "Mary had a little lamb".split_inclusive(' '); - /// 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(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} - /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// This struct is created by the [`encode_utf16`] method on [`str`]. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c4f2e283eb3bc..f4f78e1cfff95 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -13,8 +13,11 @@ mod iter; mod traits; mod validations; -use self::pattern::Pattern; -use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; +use self::iter::{ + SplitEndsInternal, SplitInclusiveInternal, SplitInitiatorInternal, SplitLeftInclusiveInternal, + SplitTerminatorInternal, +}; +use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; use crate::mem; @@ -69,12 +72,19 @@ pub use iter::SplitAsciiWhitespace; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::SplitInclusive; +#[unstable(feature = "split_inclusive_variants", issue = "none")] +pub use iter::{ + RSplitEnds, RSplitInclusive, RSplitInitiator, RSplitLeftInclusive, RSplitNInclusive, + RSplitNLeftInclusive, SplitEnds, SplitInitiator, SplitLeftInclusive, SplitNInclusive, + SplitNLeftInclusive, +}; + #[unstable(feature = "str_internals", issue = "none")] pub use validations::{next_code_point, utf8_char_width}; use iter::MatchIndicesInternal; +use iter::MatchesInternal; use iter::SplitInternal; -use iter::{MatchesInternal, SplitNInternal}; #[inline(never)] #[cold] @@ -1323,13 +1333,59 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - Split(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_trailing_empty: true, - finished: false, - }) + Split(SplitInternal::new(self, pat)) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern and yielded in reverse order. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split`] method can be used. + /// + /// [`split`]: str::split + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); + /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// + /// let v: Vec<&str> = "".rsplit('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "def", "abc"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplit(self.split(pat).0) } /// An iterator over substrings of this string slice, separated by @@ -1360,20 +1416,168 @@ impl str { /// .split_inclusive('\n').collect(); /// assert_eq!(v, ["Mary had a little lamb\n", "little lamb\n", "little lamb.\n"]); /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// let v: Vec<&str> = "".split_inclusive('\n').collect(); + /// assert_eq!(v.len(), 0); + /// ``` #[stable(feature = "split_inclusive", since = "1.51.0")] #[inline] pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> { - SplitInclusive(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_trailing_empty: false, - finished: false, - }) + SplitInclusive(SplitInclusiveInternal::new(self, pat)) + } + + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern and yielded in reverse order. Differs + /// from the iterator produced by `rsplit` in that `rsplit_inclusive` leaves + /// the matched part as the terminator of the substring. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." + /// .rsplit_inclusive('\n').collect(); + /// assert_eq!(v, ["little lamb.", "little lamb\n", "Mary had a little lamb\n"]); + /// ``` + /// + /// If the last element of the string is matched, + /// that element will be considered the terminator of the preceding substring. + /// That substring will be the first item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb.\n" + /// .rsplit_inclusive('\n').collect(); + /// assert_eq!(v, ["little lamb.\n", "little lamb\n", "Mary had a little lamb\n"]); + /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "".rsplit_inclusive('\n').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_inclusive<'a, P>(&'a self, pat: P) -> RSplitInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitInclusive(self.split_inclusive(pat).0) + } + + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern. Differs from the iterator produced by + /// `split` in that `split_left_inclusive` leaves the matched part as the + /// initiator of the substring. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." + /// .split_left_inclusive('\n').collect(); + /// assert_eq!(v, ["Mary had a little lamb", "\nlittle lamb", "\nlittle lamb."]); + /// ``` + /// + /// If the last element of the string is matched, + /// that element will be considered the initiator of a new substring. + /// That substring will be the last item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" + /// .split_left_inclusive('\n').collect(); + /// assert_eq!(v, ["\nMary had a little lamb", "\nlittle lamb", "\nlittle lamb.", "\n"]); + /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "".split_left_inclusive('\n').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_left_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitLeftInclusive<'a, P> { + SplitLeftInclusive(SplitLeftInclusiveInternal::new(self, pat)) + } + + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern and yielded in reverse order. Differs + /// from the iterator produced by `rsplit` in that `rsplit_left_inclusive` + /// leaves the matched part as the initiator of the substring. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." + /// .rsplit_left_inclusive('\n').collect(); + /// assert_eq!(v, ["\nlittle lamb.", "\nlittle lamb", "Mary had a little lamb"]); + /// ``` + /// + /// If the last element of the string is matched, + /// that element will be considered the terminator of the preceding substring. + /// That substring will be the first item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" + /// .rsplit_left_inclusive('\n').collect(); + /// assert_eq!(v, ["\n", "\nlittle lamb.", "\nlittle lamb", "\nMary had a little lamb"]); + /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let o = "".rsplit_left_inclusive('\n').next(); + /// assert_eq!(o, None); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_left_inclusive<'a, P>(&'a self, pat: P) -> RSplitLeftInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitLeftInclusive(self.split_left_inclusive(pat).0) } /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern and yielded in reverse order. + /// characters matched by a pattern. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1381,47 +1585,96 @@ impl str { /// [`char`]: prim@char /// [pattern]: self::pattern /// + /// Equivalent to [`split`], except that the leading substring + /// is skipped if empty. + /// + /// [`split`]: str::split + /// + /// This method can be used for string data that is _initiated_, + /// rather than _separated_ by a pattern. + /// /// # Iterator behavior /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, e.g., [`char`], but not for `&str`. /// - /// For iterating from the front, the [`split`] method can be used. + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_initiator`] method can be used. /// - /// [`split`]: str::split + /// [`rsplit_initiator`]: str::rsplit_initiator /// /// # Examples /// - /// Simple patterns: + /// Basic usage: /// /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); - /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// #![feature(split_inclusive_variants)] /// - /// let v: Vec<&str> = "".rsplit('X').collect(); - /// assert_eq!(v, [""]); + /// let v: Vec<&str> = ".A.B".split_initiator('.').collect(); + /// assert_eq!(v, ["A", "B"]); /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// let v: Vec<&str> = "..A..B".split_initiator(".").collect(); + /// assert_eq!(v, ["", "A", "", "B"]); /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); - /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// let v: Vec<&str> = "A.B:C.D".split_initiator(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["A", "B", "C", "D"]); /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_initiator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInitiator<'a, P> { + SplitInitiator(SplitInitiatorInternal::new(self, pat)) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. /// - /// A more complex pattern, using a closure: + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`rsplit`], except that the leading substring is + /// skipped if empty. + /// + /// [`rsplit`]: str::rsplit + /// + /// This method can be used for string data that is _initiated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_initiator`] method can be + /// used. + /// + /// [`split_initiator`]: str::split_initiator + /// + /// # Examples /// /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "def", "abc"]); + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B".rsplit_initiator('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "..A..B".rsplit_initiator(".").collect(); + /// assert_eq!(v, ["B", "", "A", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".rsplit_initiator(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["D", "C", "B", "A"]); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> + pub fn rsplit_initiator<'a, P>(&'a self, pat: P) -> RSplitInitiator<'a, P> where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - RSplit(self.split(pat).0) + RSplitInitiator(self.split_initiator(pat).0) } /// An iterator over substrings of the given string slice, separated by @@ -1469,7 +1722,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 }) + SplitTerminator(SplitTerminatorInternal::new(self, pat)) } /// An iterator over substrings of `self`, separated by characters @@ -1481,10 +1734,10 @@ impl str { /// [`char`]: prim@char /// [pattern]: self::pattern /// - /// Equivalent to [`split`], except that the trailing substring is + /// Equivalent to [`rsplit`], except that the trailing substring is /// skipped if empty. /// - /// [`split`]: str::split + /// [`rsplit`]: str::rsplit /// /// This method can be used for string data that is _terminated_, /// rather than _separated_ by a pattern. @@ -1521,6 +1774,107 @@ impl str { RSplitTerminator(self.split_terminator(pat).0) } + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`split`], except that the leading and trailing + /// substrings are skipped if empty. + /// + /// [`split`]: str::split + /// + /// This method can be used for string data that _separates_, + /// rather than _is separated by_, a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, e.g., [`char`], but not for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_ends`] method can be used. + /// + /// [`rsplit_ends`]: str::rsplit_ends + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B.".split_ends('.').collect(); + /// assert_eq!(v, ["A", "B"]); + /// + /// let v: Vec<&str> = "..A..B..".split_ends(".").collect(); + /// assert_eq!(v, ["", "A", "", "B", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".split_ends(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["A", "B", "C", "D"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_ends<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitEnds<'a, P> { + SplitEnds(SplitEndsInternal::new(self, pat)) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`rsplit`], except that the leading and trailing + /// substring are skipped if empty. + /// + /// [`rsplit`]: str::rsplit + /// + /// This method can be used for string data that _separates_, + /// rather than _is separated by_, a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_ends`] method can be + /// used. + /// + /// [`split_ends`]: str::split_ends + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B.".rsplit_ends('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "..A..B..".rsplit_ends(".").collect(); + /// assert_eq!(v, ["", "B", "", "A", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".rsplit_ends(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["D", "C", "B", "A"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_ends<'a, P>(&'a self, pat: P) -> RSplitEnds<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitEnds(self.split_ends(pat).0) + } + /// An iterator over substrings of the given string slice, separated by a /// pattern, restricted to returning at most `n` items. /// @@ -1570,7 +1924,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - SplitN(SplitNInternal { iter: self.split(pat).0, count: n }) + self.split(pat).max_items(n) } /// An iterator over substrings of this string slice, separated by a @@ -1622,7 +1976,249 @@ impl str { where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - RSplitN(self.splitn(n, pat).0) + self.rsplit(pat).max_items(n) + } + + /// An iterator over substrings of the given string slice, separated by a + /// pattern, leaving the matched part as the terminator of the substring, + /// restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn_inclusive`] method can be + /// used. + /// + /// [`rsplitn_inclusive`]: str::rsplitn_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lambda".splitn_inclusive(3, ' ').collect(); + /// assert_eq!(v, ["Mary ", "had ", "a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn_inclusive(3, "X").collect(); + /// assert_eq!(v, ["lionX", "X", "tigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn_inclusive(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".splitn_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc1", "defXghi"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_inclusive<'a, P: Pattern<'a>>( + &'a self, + n: usize, + pat: P, + ) -> SplitNInclusive<'a, P> { + self.split_inclusive(pat).max_items(n) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, leaving the matched part + /// as the terminator of the substring, restricted to returning at most `n` + /// items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn_inclusive`] method can be used. + /// + /// [`splitn_inclusive`]: str::splitn_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn_inclusive(3, ' ').collect(); + /// assert_eq!(v, ["lamb", "little ", "Mary had a "]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn_inclusive(3, 'X').collect(); + /// assert_eq!(v, ["leopard", "tigerX", "lionXX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn_inclusive(2, "::").collect(); + /// assert_eq!(v, ["leopard", "lion::tiger::"]); + /// + /// let v: Vec<&str> = "".rsplitn_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".rsplitn_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "abc1defX"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_inclusive<'a, P>(&'a self, n: usize, pat: P) -> RSplitNInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + self.rsplit_inclusive(pat).max_items(n) + } + + /// An iterator over substrings of the given string slice, separated by a + /// pattern, leaving the matched part as the initiator of the substring, + /// restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn_left_inclusive`] method can be + /// used. + /// + /// [`rsplitn_left_inclusive`]: str::rsplitn_left_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lambda".splitn_left_inclusive(3, ' ').collect(); + /// assert_eq!(v, ["Mary", " had", " a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn_left_inclusive(3, "X").collect(); + /// assert_eq!(v, ["lion", "X", "XtigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn_left_inclusive(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn_left_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".splitn_left_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "1defXghi"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_left_inclusive<'a, P: Pattern<'a>>( + &'a self, + n: usize, + pat: P, + ) -> SplitNLeftInclusive<'a, P> { + self.split_left_inclusive(pat).max_items(n) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, leaving the matched part + /// as the terminator of the substring, restricted to returning at most `n` + /// items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn_left_inclusive`] method can be used. + /// + /// [`splitn_left_inclusive`]: str::splitn_left_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn_left_inclusive(3, ' ').collect(); + /// assert_eq!(v, [" lamb", " little", "Mary had a"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn_left_inclusive(3, 'X').collect(); + /// assert_eq!(v, ["Xleopard", "Xtiger", "lionX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn_left_inclusive(2, "::").collect(); + /// assert_eq!(v, ["::leopard", "lion::tiger"]); + /// + /// let v: Vec<&str> = "".rsplitn_left_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".rsplitn_left_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["Xghi", "abc1def"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_left_inclusive<'a, P>(&'a self, n: usize, pat: P) -> RSplitNLeftInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + self.rsplit_left_inclusive(pat).max_items(n) } /// Splits the string on the first occurrence of the specified delimiter and @@ -1664,6 +2260,97 @@ impl str { // SAFETY: `Searcher` is known to return valid indices. unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } } + /// Splits the string on the first occurrence of the specified delimiter and + /// returns prefix including delimiter and suffix after delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".split_once_inclusive('='), None); + /// assert_eq!("cfg=foo".split_once_inclusive('='), Some(("cfg=", "foo"))); + /// assert_eq!("cfg=foo=bar".split_once_inclusive('='), Some(("cfg=", "foo=bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_once_inclusive<'a, P: Pattern<'a>>( + &'a self, + delimiter: P, + ) -> Option<(&'a str, &'a str)> { + let (_, end) = delimiter.into_searcher(self).next_match()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..end), self.get_unchecked(end..))) } + } + + /// Splits the string on the last occurrence of the specified delimiter and + /// returns prefix including delimiter and suffix after delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".rsplit_once_inclusive('='), None); + /// assert_eq!("cfg=foo".rsplit_once_inclusive('='), Some(("cfg=", "foo"))); + /// assert_eq!("cfg=foo=bar".rsplit_once_inclusive('='), Some(("cfg=foo=", "bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_once_inclusive<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + let (_, end) = delimiter.into_searcher(self).next_match_back()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..end), self.get_unchecked(end..))) } + } + + /// Splits the string on the first occurrence of the specified delimiter and + /// returns prefix before delimiter and suffix including delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".split_once_left_inclusive('='), None); + /// assert_eq!("cfg=foo".split_once_left_inclusive('='), Some(("cfg", "=foo"))); + /// assert_eq!("cfg=foo=bar".split_once_left_inclusive('='), Some(("cfg", "=foo=bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_once_left_inclusive<'a, P: Pattern<'a>>( + &'a self, + delimiter: P, + ) -> Option<(&'a str, &'a str)> { + let (start, _) = delimiter.into_searcher(self).next_match()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..start), self.get_unchecked(start..))) } + } + + /// Splits the string on the last occurrence of the specified delimiter and + /// returns prefix before delimiter and suffix including delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".rsplit_once_left_inclusive('='), None); + /// assert_eq!("cfg=foo".rsplit_once_left_inclusive('='), Some(("cfg", "=foo"))); + /// assert_eq!("cfg=foo=bar".rsplit_once_left_inclusive('='), Some(("cfg=foo", "=bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_once_left_inclusive<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + let (start, _) = delimiter.into_searcher(self).next_match_back()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..start), self.get_unchecked(start..))) } + } /// An iterator over the disjoint matches of a pattern within the given string /// slice.