|
1 | 1 | #![warn(missing_docs)]
|
2 | 2 | #![crate_name="itertools"]
|
3 | 3 | #![cfg_attr(not(feature = "use_std"), no_std)]
|
| 4 | +#![feature(control_flow_enum)] |
4 | 5 |
|
5 | 6 | //! Extra iterator adaptors, functions and macros.
|
6 | 7 | //!
|
@@ -75,6 +76,7 @@ use std::fmt::Write;
|
75 | 76 | type VecIntoIter<T> = alloc::vec::IntoIter<T>;
|
76 | 77 | #[cfg(feature = "use_alloc")]
|
77 | 78 | use std::iter::FromIterator;
|
| 79 | +use std::ops::ControlFlow; |
78 | 80 |
|
79 | 81 | #[macro_use]
|
80 | 82 | mod impl_macros;
|
@@ -1730,7 +1732,32 @@ pub trait Itertools : Iterator {
|
1730 | 1732 | }
|
1731 | 1733 | None
|
1732 | 1734 | }
|
| 1735 | + /// Find the value of the first element satisfying a predicate or return the last element, if any. |
| 1736 | + /// |
| 1737 | + /// The iterator is not advanced past the first element found. |
| 1738 | + /// |
| 1739 | + /// ``` |
| 1740 | + /// use itertools::Itertools; |
| 1741 | + /// |
| 1742 | + /// let numbers = [1, 2, 3, 4]; |
| 1743 | + /// assert_eq!(numbers.iter().find_or_last(|x| x > 5), Some(4)); |
| 1744 | + /// ``` |
| 1745 | + fn find_or_last<P>(mut self, predicate: P) -> Option<Self::Item> |
| 1746 | + where Self: Sized, |
| 1747 | + P: FnMut(&Self::Item) -> bool, |
| 1748 | + { |
| 1749 | + #[inline] |
| 1750 | + fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(Option<T>, T) -> ControlFlow<T, Option<T>> { |
| 1751 | + move |_, x| { |
| 1752 | + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(Some(x)) } |
| 1753 | + } |
| 1754 | + } |
1733 | 1755 |
|
| 1756 | + match self.try_fold(None, check(predicate)) { |
| 1757 | + ControlFlow::Continue(x) => x, |
| 1758 | + ControlFlow::Break(x) => Some(x), |
| 1759 | + } |
| 1760 | + } |
1734 | 1761 | /// Returns `true` if the given item is present in this iterator.
|
1735 | 1762 | ///
|
1736 | 1763 | /// This method is short-circuiting. If the given item is present in this
|
|
0 commit comments