about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcollections/vec.rs51
1 files changed, 31 insertions, 20 deletions
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index 53b7ae0703b..24f8e3a2d91 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1499,26 +1499,7 @@ impl<T> ops::DerefMut for Vec<T> {
 impl<T> FromIterator<T> for Vec<T> {
     #[inline]
     fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> {
-        // Unroll the first iteration, as the vector is going to be
-        // expanded on this iteration in every case when the iterable is not
-        // empty, but the loop in extend_desugared() is not going to see the
-        // vector being full in the few subsequent loop iterations.
-        // So we get better branch prediction.
-        let mut iterator = iter.into_iter();
-        let mut vector = match iterator.next() {
-            None => return Vec::new(),
-            Some(element) => {
-                let (lower, _) = iterator.size_hint();
-                let mut vector = Vec::with_capacity(lower.saturating_add(1));
-                unsafe {
-                    ptr::write(vector.get_unchecked_mut(0), element);
-                    vector.set_len(1);
-                }
-                vector
-            }
-        };
-        vector.extend_desugared(iterator);
-        vector
+        <Self as SpecExtend<_>>::from_iter(iter.into_iter())
     }
 }
 
@@ -1590,13 +1571,37 @@ impl<T> Extend<T> for Vec<T> {
     }
 }
 
+// Specialization trait used for Vec::from_iter and Vec::extend
 trait SpecExtend<I> {
+    fn from_iter(iter: I) -> Self;
     fn spec_extend(&mut self, iter: I);
 }
 
 impl<I, T> SpecExtend<I> for Vec<T>
     where I: Iterator<Item=T>,
 {
+    default fn from_iter(mut iterator: I) -> Self {
+        // Unroll the first iteration, as the vector is going to be
+        // expanded on this iteration in every case when the iterable is not
+        // empty, but the loop in extend_desugared() is not going to see the
+        // vector being full in the few subsequent loop iterations.
+        // So we get better branch prediction.
+        let mut vector = match iterator.next() {
+            None => return Vec::new(),
+            Some(element) => {
+                let (lower, _) = iterator.size_hint();
+                let mut vector = Vec::with_capacity(lower.saturating_add(1));
+                unsafe {
+                    ptr::write(vector.get_unchecked_mut(0), element);
+                    vector.set_len(1);
+                }
+                vector
+            }
+        };
+        vector.spec_extend(iterator);
+        vector
+    }
+
     default fn spec_extend(&mut self, iter: I) {
         self.extend_desugared(iter)
     }
@@ -1605,6 +1610,12 @@ impl<I, T> SpecExtend<I> for Vec<T>
 impl<I, T> SpecExtend<I> for Vec<T>
     where I: TrustedLen<Item=T>,
 {
+    fn from_iter(iterator: I) -> Self {
+        let mut vector = Vec::new();
+        vector.spec_extend(iterator);
+        vector
+    }
+
     fn spec_extend(&mut self, iterator: I) {
         // This is the case for a TrustedLen iterator.
         let (low, high) = iterator.size_hint();