diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 29230b1665380..acc577b7bb93f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2827,6 +2827,43 @@ pub trait Iterator { self.try_fold((), check(f)) == ControlFlow::Break(()) } + /// Tests whether a value is contained in the iterator. + /// + /// `contains()` is short-circuiting; in other words, it will stop processing + /// as soon as the function finds the item in the `Iterator`. + /// + /// This method checks the whole iterator, which is O(n). If the iterator is a sorted + /// slice, [`binary_search`](slice::binary_search) may be faster. If this is an iterator + /// on collections that have a `.contains()` or `.contains_key()` method (such as + /// `HashMap` or `BtreeSet`), using those methods directly will be faster. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_contains)] + /// assert!([1, 2, 3].iter().contains(&2)); + /// assert!(![1, 2, 3].iter().contains(&5)); + /// ``` + /// + /// [`Iterator::contains`] can be used where [`slice::contains`] cannot be used: + /// + /// ``` + /// #![feature(iter_contains)] + /// let s = [String::from("a"), String::from("b"), String::from("c")]; + /// assert!(s.iter().contains("b")); + /// ``` + #[inline] + #[unstable(feature = "iter_contains", issue = "127494")] + fn contains(&mut self, item: Q) -> bool + where + Q: PartialEq + ?Sized, + Self: Sized, + { + self.any(|elem| item == elem) + } + /// Searches for an element of an iterator that satisfies a predicate. /// /// `find()` takes a closure that returns `true` or `false`. It applies diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 962b0cea4a4f1..879fb1409d5ee 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -113,6 +113,7 @@ #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] +#![feature(iter_contains)] #![feature(link_cfg)] #![feature(offset_of_enum)] #![feature(panic_internals)] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index d2985d8a18669..6c1e0dc2e8141 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -331,6 +331,14 @@ impl Iterator for Bytes<'_> { self.0.any(f) } + #[inline] + fn contains(&mut self, item: Q) -> bool + where + Q: PartialEq + ?Sized, + { + self.0.contains(item) + } + #[inline] fn find

(&mut self, predicate: P) -> Option where diff --git a/library/coretests/tests/iter/traits/iterator.rs b/library/coretests/tests/iter/traits/iterator.rs index 5ef1f797ae55d..8fd7b5d2db7bc 100644 --- a/library/coretests/tests/iter/traits/iterator.rs +++ b/library/coretests/tests/iter/traits/iterator.rs @@ -274,6 +274,17 @@ fn test_any() { assert!(!v[..0].iter().any(|_| panic!())); } +#[test] +fn test_iterator_contains() { + let v: Box<[i32]> = Box::new([1, 2, 3, 4, 5]); + assert!(v.iter().contains(&3)); + assert_eq!(v.iter().contains(&3), v.iter().any(|&x| x == 3)); + assert!(!v.iter().contains(&10)); + assert_eq!(v.iter().contains(&10), v.iter().any(|&x| x == 10)); + assert!(Iterator::contains(&mut (1..=5), 3)); + assert!(!Iterator::contains(&mut (1..=5), 10)); +} + #[test] fn test_find() { let v: &[isize] = &[1, 3, 9, 27, 103, 14, 11]; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index b28e7338859c4..d191d23377d7c 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -70,6 +70,7 @@ #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_collect_into)] +#![feature(iter_contains)] #![feature(iter_intersperse)] #![feature(iter_is_partitioned)] #![feature(iter_map_windows)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index 1ae5f6491744a..45af9feafbdf9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -377,7 +377,7 @@ fn augment_references_with_imports( fn find_assignment_usage(name: &ast::NameLike) -> Option { let bin_expr = name.syntax().ancestors().find_map(ast::BinExpr::cast)?; - if !bin_expr.lhs()?.syntax().descendants().contains(name.syntax()) { + if !Itertools::contains(&mut bin_expr.lhs()?.syntax().descendants(), name.syntax()) { cov_mark::hit!(dont_assign_incorrect_ref); return None; } @@ -443,7 +443,7 @@ fn find_method_call_expr_usage(name: &ast::NameLike) -> Option { let method_call = name.syntax().ancestors().find_map(ast::MethodCallExpr::cast)?; let receiver = method_call.receiver()?; - if !receiver.syntax().descendants().contains(name.syntax()) { + if !Itertools::contains(&mut receiver.syntax().descendants(), name.syntax()) { return None; } diff --git a/tests/ui/suggestions/deref-path-method.rs b/tests/ui/suggestions/deref-path-method.rs index 0281cdb6b37cf..dda3470bb82fa 100644 --- a/tests/ui/suggestions/deref-path-method.rs +++ b/tests/ui/suggestions/deref-path-method.rs @@ -1,6 +1,6 @@ fn main() { let vec = Vec::new(); Vec::contains(&vec, &0); - //~^ ERROR no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope + //~^ ERROR `Vec<_, _>` is not an iterator //~| HELP the function `contains` is implemented on `[_]` } diff --git a/tests/ui/suggestions/deref-path-method.stderr b/tests/ui/suggestions/deref-path-method.stderr index 0dec424555ed5..794e5fd9aa7b5 100644 --- a/tests/ui/suggestions/deref-path-method.stderr +++ b/tests/ui/suggestions/deref-path-method.stderr @@ -1,8 +1,8 @@ -error[E0599]: no function or associated item named `contains` found for struct `Vec<_, _>` in the current scope +error[E0599]: `Vec<_, _>` is not an iterator --> $DIR/deref-path-method.rs:3:10 | LL | Vec::contains(&vec, &0); - | ^^^^^^^^ function or associated item not found in `Vec<_, _>` + | ^^^^^^^^ `Vec<_, _>` is not an iterator | note: if you're trying to build a new `Vec<_, _>` consider using one of the following associated functions: Vec::::new @@ -11,6 +11,9 @@ note: if you're trying to build a new `Vec<_, _>` consider using one of the foll Vec::::from_raw_parts and 7 others --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + = note: the following trait bounds were not satisfied: + `Vec<_, _>: Iterator` + which is required by `&mut Vec<_, _>: Iterator` help: the function `contains` is implemented on `[_]` | LL - Vec::contains(&vec, &0);