summaryrefslogtreecommitdiffstats
path: root/library/core/src/iter/traits
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /library/core/src/iter/traits
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/core/src/iter/traits')
-rw-r--r--library/core/src/iter/traits/collect.rs6
-rw-r--r--library/core/src/iter/traits/double_ended.rs62
-rw-r--r--library/core/src/iter/traits/iterator.rs222
3 files changed, 283 insertions, 7 deletions
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 0675e5635..e0ef5071c 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -138,8 +138,6 @@ pub trait FromIterator<A>: Sized {
///
/// # Examples
///
- /// Basic usage:
- ///
/// ```
/// let five_fives = std::iter::repeat(5).take(5);
///
@@ -255,8 +253,6 @@ pub trait IntoIterator {
///
/// # Examples
///
- /// Basic usage:
- ///
/// ```
/// let v = [1, 2, 3];
/// let mut iter = v.into_iter();
@@ -363,8 +359,6 @@ pub trait Extend<A> {
///
/// # Examples
///
- /// Basic usage:
- ///
/// ```
/// // You can extend a String with some chars:
/// let mut message = String::from("abc");
diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs
index 182d9f758..4c8af4eba 100644
--- a/library/core/src/iter/traits/double_ended.rs
+++ b/library/core/src/iter/traits/double_ended.rs
@@ -379,4 +379,66 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
fn nth_back(&mut self, n: usize) -> Option<I::Item> {
(**self).nth_back(n)
}
+ fn rfold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.spec_rfold(init, f)
+ }
+ fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ self.spec_try_rfold(init, f)
+ }
+}
+
+/// Helper trait to specialize `rfold` and `rtry_fold` for `&mut I where I: Sized`
+trait DoubleEndedIteratorRefSpec: DoubleEndedIterator {
+ fn spec_rfold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B;
+
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+}
+
+impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIteratorRefSpec for &mut I {
+ default fn spec_rfold<B, F>(self, init: B, mut f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next_back() {
+ accum = f(accum, x);
+ }
+ accum
+ }
+
+ default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next_back() {
+ accum = f(accum, x)?;
+ }
+ try { accum }
+ }
+}
+
+impl<I: DoubleEndedIterator> DoubleEndedIteratorRefSpec for &mut I {
+ impl_fold_via_try_fold! { spec_rfold -> spec_try_rfold }
+
+ fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ (**self).try_rfold(init, f)
+ }
}
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 988352283..ac1fc26a1 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -10,7 +10,8 @@ use super::super::{ArrayChunks, Chain, Cloned, Copied, Cycle, Enumerate, Filter,
use super::super::{FlatMap, Flatten};
use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
use super::super::{
- Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
+ Inspect, Map, MapWhile, MapWindows, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take,
+ TakeWhile,
};
fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
@@ -1591,6 +1592,163 @@ pub trait Iterator {
Flatten::new(self)
}
+ /// Calls the given function `f` for each contiguous window of size `N` over
+ /// `self` and returns an iterator over the outputs of `f`. Like [`slice::windows()`],
+ /// the windows during mapping overlap as well.
+ ///
+ /// In the following example, the closure is called three times with the
+ /// arguments `&['a', 'b']`, `&['b', 'c']` and `&['c', 'd']` respectively.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let strings = "abcd".chars()
+ /// .map_windows(|[x, y]| format!("{}+{}", x, y))
+ /// .collect::<Vec<String>>();
+ ///
+ /// assert_eq!(strings, vec!["a+b", "b+c", "c+d"]);
+ /// ```
+ ///
+ /// Note that the const parameter `N` is usually inferred by the
+ /// destructured argument in the closure.
+ ///
+ /// The returned iterator yields 𝑘 − `N` + 1 items (where 𝑘 is the number of
+ /// items yielded by `self`). If 𝑘 is less than `N`, this method yields an
+ /// empty iterator.
+ ///
+ /// The returned iterator implements [`FusedIterator`], because once `self`
+ /// returns `None`, even if it returns a `Some(T)` again in the next iterations,
+ /// we cannot put it into a contigious array buffer, and thus the returned iterator
+ /// should be fused.
+ ///
+ /// [`slice::windows()`]: slice::windows
+ /// [`FusedIterator`]: crate::iter::FusedIterator
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N` is 0. This check will most probably get changed to a
+ /// compile time error before this method gets stabilized.
+ ///
+ /// ```should_panic
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let iter = std::iter::repeat(0).map_windows(|&[]| ());
+ /// ```
+ ///
+ /// # Examples
+ ///
+ /// Building the sums of neighboring numbers.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let mut it = [1, 3, 8, 1].iter().map_windows(|&[a, b]| a + b);
+ /// assert_eq!(it.next(), Some(4)); // 1 + 3
+ /// assert_eq!(it.next(), Some(11)); // 3 + 8
+ /// assert_eq!(it.next(), Some(9)); // 8 + 1
+ /// assert_eq!(it.next(), None);
+ /// ```
+ ///
+ /// Since the elements in the following example implement `Copy`, we can
+ /// just copy the array and get an iterator over the windows.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let mut it = "ferris".chars().map_windows(|w: &[_; 3]| *w);
+ /// assert_eq!(it.next(), Some(['f', 'e', 'r']));
+ /// assert_eq!(it.next(), Some(['e', 'r', 'r']));
+ /// assert_eq!(it.next(), Some(['r', 'r', 'i']));
+ /// assert_eq!(it.next(), Some(['r', 'i', 's']));
+ /// assert_eq!(it.next(), None);
+ /// ```
+ ///
+ /// You can also use this function to check the sortedness of an iterator.
+ /// For the simple case, rather use [`Iterator::is_sorted`].
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// let mut it = [0.5, 1.0, 3.5, 3.0, 8.5, 8.5, f32::NAN].iter()
+ /// .map_windows(|[a, b]| a <= b);
+ ///
+ /// assert_eq!(it.next(), Some(true)); // 0.5 <= 1.0
+ /// assert_eq!(it.next(), Some(true)); // 1.0 <= 3.5
+ /// assert_eq!(it.next(), Some(false)); // 3.5 <= 3.0
+ /// assert_eq!(it.next(), Some(true)); // 3.0 <= 8.5
+ /// assert_eq!(it.next(), Some(true)); // 8.5 <= 8.5
+ /// assert_eq!(it.next(), Some(false)); // 8.5 <= NAN
+ /// assert_eq!(it.next(), None);
+ /// ```
+ ///
+ /// For non-fused iterators, they are fused after `map_windows`.
+ ///
+ /// ```
+ /// #![feature(iter_map_windows)]
+ ///
+ /// #[derive(Default)]
+ /// struct NonFusedIterator {
+ /// state: i32,
+ /// }
+ ///
+ /// impl Iterator for NonFusedIterator {
+ /// type Item = i32;
+ ///
+ /// fn next(&mut self) -> Option<i32> {
+ /// let val = self.state;
+ /// self.state = self.state + 1;
+ ///
+ /// // yields `0..5` first, then only even numbers since `6..`.
+ /// if val < 5 || val % 2 == 0 {
+ /// Some(val)
+ /// } else {
+ /// None
+ /// }
+ /// }
+ /// }
+ ///
+ ///
+ /// let mut iter = NonFusedIterator::default();
+ ///
+ /// // yields 0..5 first.
+ /// assert_eq!(iter.next(), Some(0));
+ /// assert_eq!(iter.next(), Some(1));
+ /// assert_eq!(iter.next(), Some(2));
+ /// assert_eq!(iter.next(), Some(3));
+ /// assert_eq!(iter.next(), Some(4));
+ /// // then we can see our iterator going back and forth
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), Some(6));
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), Some(8));
+ /// assert_eq!(iter.next(), None);
+ ///
+ /// // however, with `.map_windows()`, it is fused.
+ /// let mut iter = NonFusedIterator::default()
+ /// .map_windows(|arr: &[_; 2]| *arr);
+ ///
+ /// assert_eq!(iter.next(), Some([0, 1]));
+ /// assert_eq!(iter.next(), Some([1, 2]));
+ /// assert_eq!(iter.next(), Some([2, 3]));
+ /// assert_eq!(iter.next(), Some([3, 4]));
+ /// assert_eq!(iter.next(), None);
+ ///
+ /// // it will always return `None` after the first time.
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_map_windows", reason = "recently added", issue = "87155")]
+ #[rustc_do_not_const_check]
+ fn map_windows<F, R, const N: usize>(self, f: F) -> MapWindows<Self, F, N>
+ where
+ Self: Sized,
+ F: FnMut(&[Self::Item; N]) -> R,
+ {
+ MapWindows::new(self, f)
+ }
+
/// Creates an iterator which ends after the first [`None`].
///
/// After an iterator returns [`None`], future calls may or may not yield
@@ -4018,4 +4176,66 @@ impl<I: Iterator + ?Sized> Iterator for &mut I {
fn nth(&mut self, n: usize) -> Option<Self::Item> {
(**self).nth(n)
}
+ fn fold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ self.spec_fold(init, f)
+ }
+ fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ self.spec_try_fold(init, f)
+ }
+}
+
+/// Helper trait to specialize `fold` and `try_fold` for `&mut I where I: Sized`
+trait IteratorRefSpec: Iterator {
+ fn spec_fold<B, F>(self, init: B, f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B;
+
+ fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>;
+}
+
+impl<I: Iterator + ?Sized> IteratorRefSpec for &mut I {
+ default fn spec_fold<B, F>(self, init: B, mut f: F) -> B
+ where
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next() {
+ accum = f(accum, x);
+ }
+ accum
+ }
+
+ default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ let mut accum = init;
+ while let Some(x) = self.next() {
+ accum = f(accum, x)?;
+ }
+ try { accum }
+ }
+}
+
+impl<I: Iterator> IteratorRefSpec for &mut I {
+ impl_fold_via_try_fold! { spec_fold -> spec_try_fold }
+
+ fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R
+ where
+ F: FnMut(B, Self::Item) -> R,
+ R: Try<Output = B>,
+ {
+ (**self).try_fold(init, f)
+ }
}