Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a62c9fa
Update tracking issue numbers for inline assembly sub-features
Amanieu Jan 26, 2022
ae32f43
fix assumption that ScalarPair Box is always a fat pointer
beepster4096 Feb 16, 2022
5136b54
Unify sidebar a bit more by generating a list using <ul> instead of <…
GuillaumeGomez Feb 8, 2022
0d928b6
Update rustdoc tests to adapt to changes to the sidebar
GuillaumeGomez Feb 8, 2022
60f969a
Adopt let_else in even more places
est31 Feb 15, 2022
47d5196
Add a `try_collect()` helper method to `Iterator`
a-lafrance Feb 16, 2022
d0b508e
add comment explaining the check
beepster4096 Feb 17, 2022
80fde23
Add MAIN_SEPARATOR_STR
SUPERCILEX Feb 13, 2022
94f0849
Improve comments about type folding/visiting.
nnethercote Feb 8, 2022
94fd78d
Remove CFG_PLATFORM
bjorn3 Feb 17, 2022
7fa0c20
Don't lint `needless_borrow` in method receiver positions
Jarcho Feb 17, 2022
6733170
Rollup merge of #93337 - Amanieu:asm_tracking, r=tmiasko
matthiaskrgr Feb 17, 2022
98c54c8
Rollup merge of #93758 - nnethercote:improve-folding-comments, r=BoxyUwU
matthiaskrgr Feb 17, 2022
6a2b612
Rollup merge of #93780 - GuillaumeGomez:links-in-sidebar, r=jsha
matthiaskrgr Feb 17, 2022
09350d2
Rollup merge of #93976 - SUPERCILEX:separator_str, r=yaahc
matthiaskrgr Feb 17, 2022
637d8b8
Rollup merge of #94011 - est31:let_else, r=lcnr
matthiaskrgr Feb 17, 2022
a4be35e
Rollup merge of #94041 - a-lafrance:try-collect, r=scottmcm
matthiaskrgr Feb 17, 2022
6dc62f4
Rollup merge of #94043 - DrMeepster:box_alloc_ice, r=oli-obk
matthiaskrgr Feb 17, 2022
e1bf069
Rollup merge of #94082 - bjorn3:remove_cfg_platform, r=Mark-Simulacrum
matthiaskrgr Feb 17, 2022
39c1748
Rollup merge of #94085 - flip1995:clippy_needless_borrow_temp_fix, r=…
matthiaskrgr Feb 17, 2022
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
82 changes: 82 additions & 0 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::cmp::{self, Ordering};
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};

use super::super::try_process;
use super::super::TrustedRandomAccessNoCoerce;
use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
use super::super::{FlatMap, Flatten};
Expand Down Expand Up @@ -1777,6 +1778,87 @@ pub trait Iterator {
FromIterator::from_iter(self)
}

/// Fallibly transforms an iterator into a collection, short circuiting if
/// a failure is encountered.
///
/// `try_collect()` is a variation of [`collect()`][`collect`] that allows fallible
/// conversions during collection. Its main use case is simplifying conversions from
/// iterators yielding [`Option<T>`][`Option`] into `Option<Collection<T>>`, or similarly for other [`Try`]
/// types (e.g. [`Result`]).
///
/// Importantly, `try_collect()` doesn't require that the outer [`Try`] type also implements [`FromIterator`];
/// only the inner type produced on `Try::Output` must implement it. Concretely,
/// this means that collecting into `ControlFlow<_, Vec<i32>>` is valid because `Vec<i32>` implements
/// [`FromIterator`], even though [`ControlFlow`] doesn't.
///
/// Also, if a failure is encountered during `try_collect()`, the iterator is still valid and
/// may continue to be used, in which case it will continue iterating starting after the element that
/// triggered the failure. See the last example below for an example of how this works.
///
/// # Examples
/// Successfully collecting an iterator of `Option<i32>` into `Option<Vec<i32>>`:
/// ```
/// #![feature(iterator_try_collect)]
///
/// let u = vec![Some(1), Some(2), Some(3)];
/// let v = u.into_iter().try_collect::<Vec<i32>>();
/// assert_eq!(v, Some(vec![1, 2, 3]));
/// ```
///
/// Failing to collect in the same way:
/// ```
/// #![feature(iterator_try_collect)]
///
/// let u = vec![Some(1), Some(2), None, Some(3)];
/// let v = u.into_iter().try_collect::<Vec<i32>>();
/// assert_eq!(v, None);
/// ```
///
/// A similar example, but with `Result`:
/// ```
/// #![feature(iterator_try_collect)]
///
/// let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
/// let v = u.into_iter().try_collect::<Vec<i32>>();
/// assert_eq!(v, Ok(vec![1, 2, 3]));
///
/// let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
/// let v = u.into_iter().try_collect::<Vec<i32>>();
/// assert_eq!(v, Err(()));
/// ```
///
/// Finally, even [`ControlFlow`] works, despite the fact that it
/// doesn't implement [`FromIterator`]. Note also that the iterator can
/// continue to be used, even if a failure is encountered:
///
/// ```
/// #![feature(iterator_try_collect)]
///
/// use core::ops::ControlFlow::{Break, Continue};
///
/// let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
/// let mut it = u.into_iter();
///
/// let v = it.try_collect::<Vec<_>>();
/// assert_eq!(v, Break(3));
///
/// let v = it.try_collect::<Vec<_>>();
/// assert_eq!(v, Continue(vec![4, 5]));
/// ```
///
/// [`collect`]: Iterator::collect
#[inline]
#[unstable(feature = "iterator_try_collect", issue = "94047")]
fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B>
where
Self: Sized,
<Self as Iterator>::Item: Try,
<<Self as Iterator>::Item as Try>::Residual: Residual<B>,
B: FromIterator<<Self::Item as Try>::Output>,
{
try_process(self, |i| i.collect())
}

/// Consumes an iterator, creating two collections from it.
///
/// The predicate passed to `partition()` can return `true`, or `false`.
Expand Down
46 changes: 46 additions & 0 deletions library/core/tests/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,52 @@ fn test_collect() {
assert!(a == b);
}

#[test]
fn test_try_collect() {
use core::ops::ControlFlow::{Break, Continue};

let u = vec![Some(1), Some(2), Some(3)];
let v = u.into_iter().try_collect::<Vec<i32>>();
assert_eq!(v, Some(vec![1, 2, 3]));

let u = vec![Some(1), Some(2), None, Some(3)];
let mut it = u.into_iter();
let v = it.try_collect::<Vec<i32>>();
assert_eq!(v, None);
let v = it.try_collect::<Vec<i32>>();
assert_eq!(v, Some(vec![3]));

let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
let v = u.into_iter().try_collect::<Vec<i32>>();
assert_eq!(v, Ok(vec![1, 2, 3]));

let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
let v = u.into_iter().try_collect::<Vec<i32>>();
assert_eq!(v, Err(()));

let numbers = vec![1, 2, 3, 4, 5];
let all_positive = numbers
.iter()
.cloned()
.map(|n| if n > 0 { Some(n) } else { None })
.try_collect::<Vec<i32>>();
assert_eq!(all_positive, Some(numbers));

let numbers = vec![-2, -1, 0, 1, 2];
let all_positive =
numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::<Vec<i32>>();
assert_eq!(all_positive, None);

let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
let mut it = u.into_iter();

let v = it.try_collect::<Vec<_>>();
assert_eq!(v, Break(3));

let v = it.try_collect::<Vec<_>>();
assert_eq!(v, Continue(vec![4, 5]));
}

// just tests by whether or not this compiles
fn _empty_impl_all_auto_traits<T>() {
use std::panic::{RefUnwindSafe, UnwindSafe};
Expand Down
1 change: 1 addition & 0 deletions library/core/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
#![feature(iter_order_by)]
#![feature(iterator_try_collect)]
#![feature(iterator_try_reduce)]
#![feature(const_mut_refs)]
#![feature(const_pin)]
Expand Down