about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/iter/traits/iterator.rs37
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/tests/iter.rs40
-rw-r--r--src/libcore/tests/lib.rs1
4 files changed, 79 insertions, 0 deletions
diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs
index 25be26491e3..c958289b2c9 100644
--- a/src/libcore/iter/traits/iterator.rs
+++ b/src/libcore/iter/traits/iterator.rs
@@ -2104,6 +2104,43 @@ pub trait Iterator {
         self.try_fold((), check(f)).break_value()
     }
 
+    /// Applies function to the elements of iterator and returns
+    /// the first non-none result or the first error.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(try_find)]
+    ///
+    /// let a = ["1", "2", "lol", "NaN", "5"];
+    ///
+    /// let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
+    ///     Ok(s.parse::<i32>()?  == search)
+    /// };
+    ///
+    /// let result = a.iter().try_find(|&&s| is_my_num(s, 2));
+    /// assert_eq!(result, Ok(Some(&"2")));
+    ///
+    /// let result = a.iter().try_find(|&&s| is_my_num(s, 5));
+    /// assert!(result.is_err());
+    /// ```
+    #[inline]
+    #[unstable(feature = "try_find", reason = "new API", issue = "63178")]
+    fn try_find<F, E, R>(&mut self, mut f: F) -> Result<Option<Self::Item>, E>
+    where
+        Self: Sized,
+        F: FnMut(&Self::Item) -> R,
+        R: Try<Ok = bool, Error = E>,
+    {
+        self.try_for_each(move |x| match f(&x).into_result() {
+            Ok(false) => LoopState::Continue(()),
+            Ok(true) => LoopState::Break(Ok(x)),
+            Err(x) => LoopState::Break(Err(x)),
+        })
+        .break_value()
+        .transpose()
+    }
+
     /// Searches for an element in an iterator, returning its index.
     ///
     /// `position()` takes a closure that returns `true` or `false`. It applies
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 8e1273c3172..6f1d69821f5 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -85,6 +85,7 @@
 #![feature(extern_types)]
 #![feature(fundamental)]
 #![feature(intrinsics)]
+#![feature(try_find)]
 #![feature(is_sorted)]
 #![feature(iter_once_with)]
 #![feature(lang_items)]
diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs
index cf28ec8a636..8b8dc941534 100644
--- a/src/libcore/tests/iter.rs
+++ b/src/libcore/tests/iter.rs
@@ -1558,6 +1558,46 @@ fn test_find_map() {
 }
 
 #[test]
+fn test_try_find() {
+    let xs: &[isize] = &[];
+    assert_eq!(xs.iter().try_find(testfn), Ok(None));
+    let xs: &[isize] = &[1, 2, 3, 4];
+    assert_eq!(xs.iter().try_find(testfn), Ok(Some(&2)));
+    let xs: &[isize] = &[1, 3, 4];
+    assert_eq!(xs.iter().try_find(testfn), Err(()));
+
+    let xs: &[isize] = &[1, 2, 3, 4, 5, 6, 7];
+    let mut iter = xs.iter();
+    assert_eq!(iter.try_find(testfn), Ok(Some(&2)));
+    assert_eq!(iter.try_find(testfn), Err(()));
+    assert_eq!(iter.next(), Some(&5));
+
+    fn testfn(x: &&isize) -> Result<bool, ()> {
+        if **x == 2 {
+            return Ok(true);
+        }
+        if **x == 4 {
+            return Err(());
+        }
+        Ok(false)
+    }
+}
+
+#[test]
+fn test_try_find_api_usability() -> Result<(), Box<dyn std::error::Error>> {
+    let a = ["1", "2"];
+
+    let is_my_num = |s: &str, search: i32| -> Result<bool, std::num::ParseIntError> {
+        Ok(s.parse::<i32>()? == search)
+    };
+
+    let val = a.iter().try_find(|&&s| is_my_num(s, 2))?;
+    assert_eq!(val, Some(&"2"));
+
+    Ok(())
+}
+
+#[test]
 fn test_position() {
     let v = &[1, 3, 9, 27, 103, 14, 11];
     assert_eq!(v.iter().position(|x| *x & 1 == 0).unwrap(), 5);
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 1f20ebc01e9..39f6133f2a6 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -11,6 +11,7 @@
 #![feature(flt2dec)]
 #![feature(fmt_internals)]
 #![feature(hashmap_internals)]
+#![feature(try_find)]
 #![feature(is_sorted)]
 #![feature(iter_once_with)]
 #![feature(pattern)]