diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 19484bfd0419f..8cda5d731aa90 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -2231,6 +2231,179 @@ pub trait Iterator {
self.try_fold((), check(predicate)).break_value()
}
+ /// Searches for an element of an iterator that satisfies a predicate, returns the first
+ /// element if no such element is found.
+ ///
+ /// `find_or_first()` takes a closure that returns `true` or `false`. It applies this closure
+ /// to each element of the iterator, and if any of them return `true`, then `find_or_first()`
+ /// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`next`]
+ /// was invoked instead, though the iterator will be empty.
+ ///
+ /// `find_or_first()` is short-circuiting; in other words, it will stop processing as soon as
+ /// closure returns `true`.
+ ///
+ /// Because `find_or_first()` takes a reference, and many iterators iterate over references,
+ /// this leads to a possibly confusing situation where the argument is a double reference. You
+ /// can see this effect in the examples below, with `&&x`.
+ ///
+ /// [`Some(element)`]: Some
+ /// [`next`]: Iterator::next
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(iter_find_or_fnl)]
+ ///
+ /// let a = [0, 1, 2, 3];
+ ///
+ /// assert_eq!(
+ /// a.iter().find_or_first(|&&x| x > 1),
+ /// Some(&2) // predicate is satisfied
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_first(|&&x| x > 10),
+ /// Some(&0) // predicate not satisfied, first element is returned
+ /// );
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_find_or_fnl", reason = "recently added", issue = "none")]
+ fn find_or_first
(&mut self, mut predicate: P) -> Option
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ match self.next() {
+ Some(item) if predicate(&item) => Some(item),
+ default => self.find(predicate).or(default),
+ }
+ }
+
+ /// Searches for an element of an iterator that satisfies a predicate, returns the `n`th
+ /// element if no such element is found.
+ ///
+ /// `find_or_nth()` takes a closure that returns `true` or `false`. It applies this closure to
+ /// each element of the iterator, and if any of them return `true`, then `find_or_nth()`
+ /// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`nth(n)`]
+ /// was invoked instead, though the iterator will be empty.
+ ///
+ /// Like most indexing operations, the count starts from zero, so if `predicate` is never
+ /// satisfied, `find_or_nth(predicate, 0)` returns the first item, `find_or_nth(1)` the second,
+ /// and so on.
+ ///
+ /// `find_or_nth()` is short-circuiting; in other words, it will stop processing as soon as the
+ /// closure returns `true`.
+ ///
+ /// Because `find_or_nth()` takes a reference, and many iterators iterate over references, this
+ /// leads to a possibly confusing situation where the argument is a double reference. You can
+ /// see this effect in the examples below, with `&&x`.
+ ///
+ /// [`Some(element)`]: Some
+ /// [`nth(n)`]: Iterator::nth
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(iter_find_or_fnl)]
+ ///
+ /// let a = [0, 1, 2, 3];
+ ///
+ /// assert_eq!(
+ /// a.iter().find_or_nth(|&&x| x > 1, 2),
+ /// Some(&2) // predicate is satisfied
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_nth(|&&x| x > 10, 2),
+ /// Some(&2) // predicate not satisfied, 3rd element is returned
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_nth(|&&x| x > 10, 5),
+ /// None // predicate not satisfied, no 6th element
+ /// );
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_find_or_fnl", reason = "recently added", issue = "none")]
+ fn find_or_nth(&mut self, predicate: P, n: usize) -> Option
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ #[inline]
+ fn check(
+ mut predicate: impl FnMut(&T) -> bool,
+ n: usize,
+ ) -> impl FnMut(Option, (usize, T)) -> ControlFlow> {
+ move |prev, (idx, cur)| {
+ if predicate(&cur) {
+ ControlFlow::Break(cur)
+ } else if idx == n {
+ debug_assert!(prev.is_none());
+ ControlFlow::Continue(Some(cur))
+ } else {
+ debug_assert_eq!(idx < n, prev.is_none());
+ ControlFlow::Continue(prev)
+ }
+ }
+ }
+
+ self.enumerate().try_fold(None, check(predicate, n)).into_result().unwrap_or_else(Some)
+ }
+
+ /// Searches for an element of an iterator that satisfies a predicate, returns the last
+ /// element if no such element is found.
+ ///
+ /// `find_or_last()` takes a closure that returns `true` or `false`. It applies this closure to
+ /// each element of the iterator, and if any of them return `true`, then `find_or_last()`
+ /// returns [`Some(element)`]. If they all return `false`, it returns the same as if [`last`]
+ /// was invoked instead.
+ ///
+ /// `find_or_last()` is short-circuiting; in other words, it will stop processing as soon as the
+ /// closure returns `true`.
+ ///
+ /// Because `find_or_last()` takes a reference, and many iterators iterate over references, this
+ /// leads to a possibly confusing situation where the argument is a double reference. You can
+ /// see this effect in the examples below, with `&&x`.
+ ///
+ /// [`Some(element)`]: Some
+ /// [`last`]: Iterator::last
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// #![feature(iter_find_or_fnl)]
+ ///
+ /// let a = [0, 1, 2, 3];
+ ///
+ /// assert_eq!(
+ /// a.iter().find_or_last(|&&x| x > 1),
+ /// Some(&2) // predicate is satisfied
+ /// );
+ /// assert_eq!(
+ /// a.iter().find_or_last(|&&x| x > 10),
+ /// Some(&3) // predicate not satisfied, last element is returned
+ /// );
+ /// ```
+ #[inline]
+ #[unstable(feature = "iter_find_or_fnl", reason = "recently added", issue = "none")]
+ fn find_or_last(&mut self, predicate: P) -> Option
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ #[inline]
+ fn check(
+ mut predicate: impl FnMut(&T) -> bool,
+ ) -> impl FnMut(Option, T) -> ControlFlow> {
+ move |_, cur| {
+ if predicate(&cur) {
+ ControlFlow::Break(cur)
+ } else {
+ ControlFlow::Continue(Some(cur))
+ }
+ }
+ }
+ self.try_fold(None, check(predicate)).into_result().unwrap_or_else(Some)
+ }
+
/// Applies function to the elements of iterator and returns
/// the first non-none result.
///
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 75ca897cadc91..013989b5d32dd 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -1930,6 +1930,62 @@ fn test_find() {
assert!(v.iter().find(|&&x| x % 12 == 0).is_none());
}
+#[test]
+fn find_or_first() {
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 1), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 2), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_first(|&&n| n > 3), Some(&0));
+ assert_eq!([3, 2, 1, 0].iter().find_or_first(|&&n| n > 1), Some(&3));
+ assert_eq!([1].iter().find_or_first(|&&n| n > 1), Some(&1));
+ assert_eq!([2].iter().find_or_first(|&&n| n > 1), Some(&2));
+ assert_eq!([(); 0].iter().find_or_first(|()| unreachable!()), None);
+}
+
+#[test]
+fn find_or_nth() {
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 0), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 1), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 2), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 3), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 1, 4), Some(&2));
+
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 0), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 1), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 2), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 3), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 2, 4), Some(&3));
+
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 0), Some(&0));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 1), Some(&1));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 2), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 3), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_nth(|&&n| n > 3, 4), None);
+
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 0), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 1), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 2), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 3), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_nth(|&&n| n > 1, 4), Some(&3));
+
+ assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 0), Some(&1));
+ assert_eq!([1].iter().find_or_nth(|&&n| n > 1, 1), None);
+ assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 0), Some(&2));
+ assert_eq!([2].iter().find_or_nth(|&&n| n > 1, 1), Some(&2));
+
+ assert_eq!([(); 0].iter().find_or_nth(|()| unreachable!(), 0), None);
+}
+
+#[test]
+fn find_or_last() {
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 1), Some(&2));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 2), Some(&3));
+ assert_eq!([0, 1, 2, 3].iter().find_or_last(|&&n| n > 3), Some(&3));
+ assert_eq!([3, 2, 1, 0].iter().find_or_last(|&&n| n > 1), Some(&3));
+ assert_eq!([1].iter().find_or_last(|&&n| n > 1), Some(&1));
+ assert_eq!([2].iter().find_or_last(|&&n| n > 1), Some(&2));
+ assert_eq!([(); 0].iter().find_or_last(|()| unreachable!()), None);
+}
+
#[test]
fn test_find_map() {
let xs: &[isize] = &[];
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 14ef03fd53eba..fabf3c36f3417 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -43,6 +43,7 @@
#![feature(int_error_matching)]
#![feature(array_value_iter)]
#![feature(iter_advance_by)]
+#![feature(iter_find_or_fnl)]
#![feature(iter_partition_in_place)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]