Skip to content

Commit a0b8ca1

Browse files
committed
Impl FromIterator for tuples with arity 1-12
1 parent 9c707a8 commit a0b8ca1

File tree

2 files changed

+66
-52
lines changed

2 files changed

+66
-52
lines changed

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

+54-52
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
@@ -595,32 +562,67 @@ macro_rules! spec_tuple_impl {
595562
Iter: TrustedLen<Item = ($($ty_names,)*)>,
596563
{
597564
fn extend(self, $($var_names: &mut $extend_ty_names,)*) {
598-
fn extend<'a, $($ty_names,)*>(
599-
$($var_names: &'a mut impl Extend<$ty_names>,)*
600-
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
601-
#[allow(non_snake_case)]
602-
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
603-
// so its `size_hint` is exact.
604-
move |(), ($($extend_ty_names,)*)| unsafe {
605-
$($var_names.extend_one_unchecked($extend_ty_names);)*
565+
fn extend<'a, $($ty_names,)*>(
566+
$($var_names: &'a mut impl Extend<$ty_names>,)*
567+
) -> impl FnMut((), ($($ty_names,)*)) + 'a {
568+
#[allow(non_snake_case)]
569+
// SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
570+
// so its `size_hint` is exact.
571+
move |(), ($($extend_ty_names,)*)| unsafe {
572+
$($var_names.extend_one_unchecked($extend_ty_names);)*
573+
}
606574
}
607-
}
608575

609-
let (lower_bound, upper_bound) = self.size_hint();
576+
let (lower_bound, upper_bound) = self.size_hint();
610577

611-
if upper_bound.is_none() {
612-
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
613-
$default_fn_name(self, $($var_names,)*);
614-
return;
615-
}
578+
if upper_bound.is_none() {
579+
// We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
580+
$default_fn_name(self, $($var_names,)*);
581+
return;
582+
}
616583

617-
if lower_bound > 0 {
618-
$($var_names.extend_reserve(lower_bound);)*
584+
if lower_bound > 0 {
585+
$($var_names.extend_reserve(lower_bound);)*
586+
}
587+
588+
self.fold((), extend($($var_names,)*));
619589
}
590+
}
620591

621-
self.fold((), extend($($var_names,)*));
592+
/// This implementation turns an iterator of tuples into a tuple of types which implement
593+
/// [`Default`] and [`Extend`].
594+
///
595+
/// This is similar to [`Iterator::unzip`], but is also composable with other [`FromIterator`]
596+
/// implementations:
597+
///
598+
/// ```rust
599+
/// # fn main() -> Result<(), core::num::ParseIntError> {
600+
/// let string = "1,2,123,4";
601+
///
602+
/// // Example given for a 2-tuple, but 1- through 12-tuples are supported
603+
/// let (numbers, lengths): (Vec<_>, Vec<_>) = string
604+
/// .split(',')
605+
/// .map(|s| s.parse().map(|n: u32| (n, s.len())))
606+
/// .collect::<Result<_, _>>()?;
607+
///
608+
/// assert_eq!(numbers, [1, 2, 123, 4]);
609+
/// assert_eq!(lengths, [1, 1, 3, 1]);
610+
/// # Ok(()) }
611+
/// ```
612+
#[$meta]
613+
$(#[$doctext])?
614+
#[stable(feature = "from_iterator_for_tuple", since = "1.79.0")]
615+
impl<$($ty_names,)* $($extend_ty_names,)*> FromIterator<($($extend_ty_names,)*)> for ($($ty_names,)*)
616+
where
617+
$($ty_names: Default + Extend<$extend_ty_names>,)*
618+
{
619+
fn from_iter<Iter: IntoIterator<Item = ($($extend_ty_names,)*)>>(iter: Iter) -> Self {
620+
let mut res = <($($ty_names,)*)>::default();
621+
res.extend(iter);
622+
623+
res
624+
}
622625
}
623-
}
624626

625627
};
626628
}

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)