Skip to content

Commit 78af7da

Browse files
committed
Auto merge of rust-lang#132431 - shahn:from_iterator_more_tuples, r=Amanieu
From iterator for more tuples
2 parents a25032c + 10b2351 commit 78af7da

File tree

2 files changed

+65
-51
lines changed

2 files changed

+65
-51
lines changed

library/core/src/iter/traits/collect.rs

+53-51
Original file line numberDiff line numberDiff line change
@@ -152,39 +152,6 @@ pub trait FromIterator<A>: Sized {
152152
fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
153153
}
154154

155-
/// This implementation turns an iterator of tuples into a tuple of types which implement
156-
/// [`Default`] and [`Extend`].
157-
///
158-
/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`]
159-
/// implementations:
160-
///
161-
/// ```rust
162-
/// # fn main() -> Result<(), core::num::ParseIntError> {
163-
/// let string = "1,2,123,4";
164-
///
165-
/// let (numbers, lengths): (Vec<_>, Vec<_>) = string
166-
/// .split(',')
167-
/// .map(|s| s.parse().map(|n: u32| (n, s.len())))
168-
/// .collect::<Result<_, _>>()?;
169-
///
170-
/// assert_eq!(numbers, [1, 2, 123, 4]);
171-
/// assert_eq!(lengths, [1, 1, 3, 1]);
172-
/// # Ok(()) }
173-
/// ```
174-
#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")]
175-
impl<A, B, AE, BE> FromIterator<(AE, BE)> for (A, B)
176-
where
177-
A: Default + Extend<AE>,
178-
B: Default + Extend<BE>,
179-
{
180-
fn from_iter<I: IntoIterator<Item = (AE, BE)>>(iter: I) -> Self {
181-
let mut res = <(A, B)>::default();
182-
res.extend(iter);
183-
184-
res
185-
}
186-
}
187-
188155
/// Conversion into an [`Iterator`].
189156
///
190157
/// By implementing `IntoIterator` for a type, you define how it will be
@@ -629,7 +596,7 @@ macro_rules! spec_tuple_impl {
629596
}
630597

631598
impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
632-
where
599+
where
633600
$($extend_ty_names: Extend<$ty_names>,)*
634601
Iter: Iterator<Item = ($($ty_names,)*)>,
635602
{
@@ -639,37 +606,72 @@ macro_rules! spec_tuple_impl {
639606
}
640607

641608
impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
642-
where
609+
where
643610
$($extend_ty_names: Extend<$ty_names>,)*
644611
Iter: TrustedLen<Item = ($($ty_names,)*)>,
645612
{
646613
fn extend(self, $($var_names: &mut $extend_ty_names,)*) {
647614
fn extend<'a, $($ty_names,)*>(
648615
$($var_names: &'a mut impl Extend<$ty_names>,)*
649616
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
650-
#[allow(non_snake_case)]
651-
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
652-
// so its `size_hint` is exact.
653-
move |(), ($($extend_ty_names,)*)| unsafe {
654-
$($var_names.extend_one_unchecked($extend_ty_names);)*
617+
#[allow(non_snake_case)]
618+
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is
619+
// `TrustedLen` so its `size_hint` is exact.
620+
move |(), ($($extend_ty_names,)*)| unsafe {
621+
$($var_names.extend_one_unchecked($extend_ty_names);)*
622+
}
655623
}
656-
}
657624

658-
let (lower_bound, upper_bound) = self.size_hint();
625+
let (lower_bound, upper_bound) = self.size_hint();
659626

660-
if upper_bound.is_none() {
661-
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
662-
$default_fn_name(self, $($var_names,)*);
663-
return;
664-
}
627+
if upper_bound.is_none() {
628+
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
629+
$default_fn_name(self, $($var_names,)*);
630+
return;
631+
}
665632

666-
if lower_bound > 0 {
667-
$($var_names.extend_reserve(lower_bound);)*
633+
if lower_bound > 0 {
634+
$($var_names.extend_reserve(lower_bound);)*
635+
}
636+
637+
self.fold((), extend($($var_names,)*));
668638
}
639+
}
669640

670-
self.fold((), extend($($var_names,)*));
641+
/// This implementation turns an iterator of tuples into a tuple of types which implement
642+
/// [`Default`] and [`Extend`].
643+
///
644+
/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`]
645+
/// implementations:
646+
///
647+
/// ```rust
648+
/// # fn main() -> Result<(), core::num::ParseIntError> {
649+
/// let string = "1,2,123,4";
650+
///
651+
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
652+
/// let (numbers, lengths): (Vec<_>, Vec<_>) = string
653+
/// .split(',')
654+
/// .map(|s| s.parse().map(|n: u32| (n, s.len())))
655+
/// .collect::<Result<_, _>>()?;
656+
///
657+
/// assert_eq!(numbers, [1, 2, 123, 4]);
658+
/// assert_eq!(lengths, [1, 1, 3, 1]);
659+
/// # Ok(()) }
660+
/// ```
661+
#[$meta]
662+
$(#[$doctext])?
663+
#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")]
664+
impl<$($ty_names,)* $($extend_ty_names,)*> FromIterator<($($extend_ty_names,)*)> for ($($ty_names,)*)
665+
where
666+
$($ty_names: Default + Extend<$extend_ty_names>,)*
667+
{
668+
fn from_iter<Iter: IntoIterator<Item = ($($extend_ty_names,)*)>>(iter: Iter) -> Self {
669+
let mut res = <($($ty_names,)*)>::default();
670+
res.extend(iter);
671+
672+
res
673+
}
671674
}
672-
}
673675

674676
};
675677
}

library/core/tests/iter/traits/iterator.rs

+12
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,18 @@ fn test_collect_into_tuples() {
630630
assert!(e.2 == d);
631631
}
632632

633+
#[test]
634+
fn test_collect_for_tuples() {
635+
let a = vec![(1, 2, 3), (4, 5, 6), (7, 8, 9)];
636+
let b = vec![1, 4, 7];
637+
let c = vec![2, 5, 8];
638+
let d = vec![3, 6, 9];
639+
let e: (Vec<_>, Vec<_>, Vec<_>) = a.into_iter().collect();
640+
assert!(e.0 == b);
641+
assert!(e.1 == c);
642+
assert!(e.2 == d);
643+
}
644+
633645
// just tests by whether or not this compiles
634646
fn _empty_impl_all_auto_traits<T>() {
635647
use std::panic::{RefUnwindSafe, UnwindSafe};

0 commit comments

Comments
 (0)