diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f296792b1dcb2..db0bfa44ccab0 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2826,6 +2826,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 989ab80b77d41..9fc87f941f4b1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -110,6 +110,7 @@ #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] +#![feature(iter_contains)] #![feature(lazy_get)] #![feature(link_cfg)] #![feature(offset_of_enum)] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 425c4eaee28ee..4f54216be9310 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 e31d2e15b6d7e..8b6e08e8c23c4 100644 --- a/library/coretests/tests/iter/traits/iterator.rs +++ b/library/coretests/tests/iter/traits/iterator.rs @@ -272,6 +272,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 dd7cdd79c0d60..68c5e36bfa771 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -55,6 +55,7 @@ #![feature(iter_array_chunks)] #![feature(iter_chain)] #![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 f73b8c4fd0f19..a7fab9d7c5608 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 @@ -378,7 +378,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; } @@ -444,7 +444,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 dc2f6f66437e0..4adae868f5a8d 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 6 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);