about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-12-26 09:11:06 +0000
committerbors <bors@rust-lang.org>2024-12-26 09:11:06 +0000
commit78af7da26d50d79b7f527b40182e4aaf541f1b37 (patch)
treedae528a65f1af201fd9ea1690a13e11c37bb5466
parenta25032cf444eeba7652ce5165a2be450430890ba (diff)
parent10b23518c1f632f67a9a7c47e742d07c4579242a (diff)
downloadrust-78af7da26d50d79b7f527b40182e4aaf541f1b37.tar.gz
rust-78af7da26d50d79b7f527b40182e4aaf541f1b37.zip
Auto merge of #132431 - shahn:from_iterator_more_tuples, r=Amanieu
From iterator for more tuples
-rw-r--r--library/core/src/iter/traits/collect.rs104
-rw-r--r--library/core/tests/iter/traits/iterator.rs12
2 files changed, 65 insertions, 51 deletions
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 8ab1c26f95e..73e6d931060 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -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
@@ -629,7 +596,7 @@ macro_rules! spec_tuple_impl {
         }
 
         impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
-            where
+        where
             $($extend_ty_names: Extend<$ty_names>,)*
             Iter: Iterator<Item = ($($ty_names,)*)>,
         {
@@ -639,7 +606,7 @@ macro_rules! spec_tuple_impl {
         }
 
         impl<$($ty_names,)* $($extend_ty_names,)* Iter> $trait_name<$($extend_ty_names),*> for Iter
-            where
+        where
             $($extend_ty_names: Extend<$ty_names>,)*
             Iter: TrustedLen<Item = ($($ty_names,)*)>,
         {
@@ -647,29 +614,64 @@ macro_rules! spec_tuple_impl {
                 fn extend<'a, $($ty_names,)*>(
                     $($var_names: &'a mut impl Extend<$ty_names>,)*
                 ) -> impl FnMut((), ($($ty_names,)*)) + 'a {
-                #[allow(non_snake_case)]
-                // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen`
-                // so its `size_hint` is exact.
-                move |(), ($($extend_ty_names,)*)| unsafe {
-                    $($var_names.extend_one_unchecked($extend_ty_names);)*
+                    #[allow(non_snake_case)]
+                    // SAFETY: We reserve enough space for the `size_hint`, and the iterator is
+                    // `TrustedLen` so its `size_hint` is exact.
+                    move |(), ($($extend_ty_names,)*)| unsafe {
+                        $($var_names.extend_one_unchecked($extend_ty_names);)*
+                    }
                 }
-            }
 
-            let (lower_bound, upper_bound) = self.size_hint();
+                let (lower_bound, upper_bound) = self.size_hint();
 
-            if upper_bound.is_none() {
-                // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
-                $default_fn_name(self, $($var_names,)*);
-                return;
-            }
+                if upper_bound.is_none() {
+                    // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway.
+                    $default_fn_name(self, $($var_names,)*);
+                    return;
+                }
 
-            if lower_bound > 0 {
-                $($var_names.extend_reserve(lower_bound);)*
+                if lower_bound > 0 {
+                    $($var_names.extend_reserve(lower_bound);)*
+                }
+
+                self.fold((), extend($($var_names,)*));
             }
+        }
 
-            self.fold((), extend($($var_names,)*));
+        /// 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
+            }
         }
-    }
 
     };
 }
diff --git a/library/core/tests/iter/traits/iterator.rs b/library/core/tests/iter/traits/iterator.rs
index 76f1e3319d4..e31d2e15b6d 100644
--- a/library/core/tests/iter/traits/iterator.rs
+++ b/library/core/tests/iter/traits/iterator.rs
@@ -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};