Skip to content

Commit

Permalink
Impl FromIterator for tuples with arity 1-12
Browse files Browse the repository at this point in the history
  • Loading branch information
shahn authored and gitbot committed Feb 20, 2025
1 parent bff596c commit 149fcf9
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 33 deletions.
68 changes: 35 additions & 33 deletions core/src/iter/traits/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,39 +152,6 @@ pub trait FromIterator<A>: Sized {
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
}

/// This implementation turns an iterator of tuples into a tuple of types which implement
/// [`Default`] and [`Extend`].
///
/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`]
/// implementations:
///
/// ```rust
/// # fn main() -> Result<(), core::num::ParseIntError> {
/// let string = "1,2,123,4";
///
/// let (numbers, lengths): (Vec<_>, Vec<_>) = string
/// .split(',')
/// .map(|s| s.parse().map(|n: u32| (n, s.len())))
/// .collect::<Result<_, _>>()?;
///
/// assert_eq!(numbers, [1, 2, 123, 4]);
/// assert_eq!(lengths, [1, 1, 3, 1]);
/// # Ok(()) }
/// ```
#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")]
impl<A, B, AE, BE> FromIterator<(AE, BE)> for (A, B)
where
A: Default + Extend<AE>,
B: Default + Extend<BE>,
{
fn from_iter<I: IntoIterator<Item = (AE, BE)>>(iter: I) -> Self {
let mut res = <(A, B)>::default();
res.extend(iter);

res
}
}

/// Conversion into an [`Iterator`].
///
/// By implementing `IntoIterator` for a type, you define how it will be
Expand Down Expand Up @@ -671,6 +638,41 @@ macro_rules! spec_tuple_impl {
}
}

/// This implementation turns an iterator of tuples into a tuple of types which implement
/// [`Default`] and [`Extend`].
///
/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`]
/// implementations:
///
/// ```rust
/// # fn main() -> Result<(), core::num::ParseIntError> {
/// let string = "1,2,123,4";
///
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
/// let (numbers, lengths): (Vec<_>, Vec<_>) = string
/// .split(',')
/// .map(|s| s.parse().map(|n: u32| (n, s.len())))
/// .collect::<Result<_, _>>()?;
///
/// assert_eq!(numbers, [1, 2, 123, 4]);
/// assert_eq!(lengths, [1, 1, 3, 1]);
/// # Ok(()) }
/// ```
#[$meta]
$(#[$doctext])?
#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")]
impl<$($ty_names,)* $($extend_ty_names,)*> FromIterator<($($extend_ty_names,)*)> for ($($ty_names,)*)
where
$($ty_names: Default + Extend<$extend_ty_names>,)*
{
fn from_iter<Iter: IntoIterator<Item = ($($extend_ty_names,)*)>>(iter: Iter) -> Self {
let mut res = <($($ty_names,)*)>::default();
res.extend(iter);

res
}
}

};
}

Expand Down
12 changes: 12 additions & 0 deletions core/tests/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,18 @@ fn test_collect_into_tuples() {
assert!(e.2 == d);
}

#[test]
fn test_collect_for_tuples() {
let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)];
let b = vec![1, 4, 7];
let c = vec![2, 5, 8];
let d = vec![3, 6, 9];
let e: (Vec<_>, Vec<_>, Vec<_>) = a.into_iter().collect();
assert!(e.0 == b);
assert!(e.1 == c);
assert!(e.2 == d);
}

// just tests by whether or not this compiles
fn _empty_impl_all_auto_traits<T>() {
use std::panic::{RefUnwindSafe, UnwindSafe};
Expand Down

0 comments on commit 149fcf9

Please sign in to comment.