diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8a2a6823fdf4b..e61cc741f3912 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -86,7 +86,8 @@ impl MetadataLoader for DefaultMetadataLoader { format!("failed to parse aix dylib '{}': {}", path.display(), e) })?; - match archive.members().exactly_one() { + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + match Itertools::exactly_one(archive.members()) { Ok(lib) => { let lib = lib.map_err(|e| { format!("failed to parse aix dylib '{}': {}", path.display(), e) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 9e081e65f9ad6..209447cccc61d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -4127,6 +4127,62 @@ pub const trait Iterator { { unreachable!("Always specialized"); } + + /// Checks if the iterator contains *exactly* one element. + /// If so, returns this one element. + /// + /// See also [`collect_array`](Iterator::collect_array) for lengths other than `1`. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_length_collection)] + /// + /// assert_eq!([1].into_iter().exactly_one(), Some(1)); + /// assert_eq!([].into_iter().exactly_one(), None::<()>); + /// + /// // There is exactly one even integer in the array: + /// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 0).exactly_one(), Some(2)); + /// // But there are two odds, which is too many: + /// assert_eq!([1, 2, 3].into_iter().filter(|x| x % 2 == 1).exactly_one(), None); + /// ``` + #[inline] + #[unstable(feature = "exact_length_collection", issue = "149266")] + fn exactly_one(self) -> Option + where + Self: Sized, + { + self.collect_array::<1>().map(|[i]| i) + } + + /// Checks if an iterator has *exactly* `N` elements. + /// If so, returns those `N` elements in an array. + /// + /// See also [`exactly_one`](Iterator::exactly_one) when expecting a single element. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_length_collection)] + /// + /// assert_eq!([1, 2, 3, 4].into_iter().collect_array(), Some([1, 2, 3, 4])); + /// assert_eq!([1, 2].into_iter().chain([3, 4]).collect_array(), Some([1, 2, 3, 4])); + /// + /// // Iterator contains too few elements: + /// assert_eq!([1, 2].into_iter().collect_array::<4>(), None); + /// // Iterator contains too many elements: + /// assert_eq!([1, 2, 3, 4, 5].into_iter().collect_array::<4>(), None); + /// // Taking 4 makes it work again: + /// assert_eq!([1, 2, 3, 4, 5].into_iter().take(4).collect_array(), Some([1, 2, 3, 4])); + /// ``` + #[inline] + #[unstable(feature = "exact_length_collection", issue = "149266")] + fn collect_array(mut self) -> Option<[Self::Item; N]> + where + Self: Sized, + { + self.next_chunk().ok().filter(|_| self.next().is_none()) + } } trait SpecIterEq: Iterator { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 7eff0b5402b48..0c70311ecff97 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1140,7 +1140,8 @@ pub(crate) fn print_impl( } if impl_.kind.is_fake_variadic() && let Some(generics) = ty.generics() - && let Ok(inner_type) = generics.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + && let Ok(inner_type) = Itertools::exactly_one(generics) { let last = ty.last(); if f.alternate() { @@ -1220,7 +1221,8 @@ impl clean::Impl { } } else if let clean::Type::Path { path } = type_ && let Some(generics) = path.generics() - && let Ok(ty) = generics.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + && let Ok(ty) = Itertools::exactly_one(generics) && self.kind.is_fake_variadic() { print_anchor(path.def_id(), path.last(), cx).fmt(f)?; diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 8e09d88232f61..82e6ab1652f58 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -91,7 +91,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id))) .then_some((v.def_id, v.span)) }); - if let Ok((id, span)) = iter.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + if let Ok((id, span)) = Itertools::exactly_one(iter) && !find_attr!(cx.tcx.hir_attrs(item.hir_id()), NonExhaustive(..)) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); @@ -103,7 +104,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { .iter() .filter(|field| !cx.effective_visibilities.is_exported(field.def_id)); if fields.len() > 1 - && let Ok(field) = private_fields.exactly_one() + // FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266 + && let Ok(field) = Itertools::exactly_one(private_fields) && let TyKind::Tup([]) = field.ty.kind { span_lint_and_then( diff --git a/tests/ui/const-generics/type-dependent/issue-71805.rs b/tests/ui/const-generics/type-dependent/issue-71805.rs index 27c101df107c8..de04a809da60f 100644 --- a/tests/ui/const-generics/type-dependent/issue-71805.rs +++ b/tests/ui/const-generics/type-dependent/issue-71805.rs @@ -4,7 +4,7 @@ use std::mem::MaybeUninit; trait CollectSlice<'a>: Iterator { fn inner_array(&mut self) -> [Self::Item; N]; - fn collect_array(&mut self) -> [Self::Item; N] { + fn custom_collect_array(&mut self) -> [Self::Item; N] { let result = self.inner_array(); assert!(self.next().is_none()); result @@ -34,5 +34,5 @@ where fn main() { let mut foos = [0u64; 9].iter().cloned(); - let _bar: [u64; 9] = foos.collect_array::<9_usize>(); + let _bar: [u64; 9] = foos.custom_collect_array::<9_usize>(); } diff --git a/tests/ui/mir/mir-inlining/ice-issue-77564.rs b/tests/ui/mir/mir-inlining/ice-issue-77564.rs index fce6d1d174f66..256ff295184d7 100644 --- a/tests/ui/mir/mir-inlining/ice-issue-77564.rs +++ b/tests/ui/mir/mir-inlining/ice-issue-77564.rs @@ -29,10 +29,11 @@ where fn main() { assert_eq!( - [[1, 2], [3, 4]] + CollectArray::collect_array( + &mut [[1, 2], [3, 4]] .iter() - .map(|row| row.iter().collect_array()) - .collect_array(), + .map(|row| CollectArray::collect_array(&mut row.iter())) + ), [[&1, &2], [&3, &4]] ); }