Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
56 changes: 56 additions & 0 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4034,6 +4034,62 @@ pub 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<Self::Item>
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<const N: usize>(mut self) -> Option<[Self::Item; N]>
where
Self: Sized,
{
self.next_chunk().ok().filter(|_| self.next().is_none())
}
}

trait SpecIterEq<B: Iterator>: Iterator {
Expand Down
6 changes: 4 additions & 2 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,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() {
Expand Down Expand Up @@ -1206,7 +1207,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)?;
Expand Down
6 changes: 4 additions & 2 deletions src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,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()), AttributeKind::NonExhaustive(..))
{
self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
Expand All @@ -104,7 +105,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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> {
&& let DelimiterKind::Parenthesis | DelimiterKind::Invisible = sub.delimiter.kind
{
tt =
tt_iter.exactly_one().map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?;
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
Itertools::exactly_one(tt_iter).map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?;
}

match tt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,8 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
let name_ref = ctx.find_node_at_offset::<ast::NameRef>()?;
let mcall = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
let receiver = mcall.receiver()?;
let closure_body = mcall.arg_list()?.args().exactly_one().ok()?;
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
let closure_body = Itertools::exactly_one(mcall.arg_list()?.args()).ok()?;
let closure_body = match closure_body {
ast::Expr::ClosureExpr(expr) => expr.body()?,
_ => return None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ fn extract_range(iterable: &ast::Expr) -> Option<(ast::Expr, Option<ast::Expr>,
(range.start()?, range.end(), make::expr_literal("1").into(), inclusive)
}
ast::Expr::MethodCallExpr(call) if call.name_ref()?.text() == "step_by" => {
let [step] = call.arg_list()?.args().collect_array()?;
let [step] = Itertools::collect_array(call.arg_list()?.args())?;
let (start, end, _, inclusive) = extract_range(&call.receiver()?)?;
(start, end, step, inclusive)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None);
let (db, position) = position(ra_fixture);
let mut actual = db.file_text(position.file_id).text(&db).to_string();
completions
.into_iter()
.exactly_one()
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
Itertools::exactly_one(completions.into_iter())
.expect("more than one completion")
.text_edit
.apply(&mut actual);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ impl Project<'_> {
let mut buf = Vec::new();
flags::Lsif::run(
flags::Lsif {
path: tmp_dir_path.join(self.roots.iter().exactly_one().unwrap()).into(),
// FIXME: rewrite in terms of `#![feature(exact_length_collection)]`. See: #149266
path: tmp_dir_path.join(Itertools::exactly_one(self.roots.iter()).unwrap()).into(),
exclude_vendored_libraries: false,
},
&mut buf,
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/type-dependent/issue-71805.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::mem::MaybeUninit;
trait CollectSlice<'a>: Iterator {
fn inner_array<const N: usize>(&mut self) -> [Self::Item; N];

fn collect_array<const N: usize>(&mut self) -> [Self::Item; N] {
fn custom_collect_array<const N: usize>(&mut self) -> [Self::Item; N] {
let result = self.inner_array();
assert!(self.next().is_none());
result
Expand Down Expand Up @@ -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>();
}
7 changes: 4 additions & 3 deletions tests/ui/mir/mir-inlining/ice-issue-77564.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
);
}
Loading